aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Dolbec <dolsen@gentoo.org>2013-06-21 18:46:22 -0700
committerBrian Dolbec <dolsen@gentoo.org>2013-06-22 16:00:47 -0700
commit5d2a88b991ac9bf93462e6b17c6abebadda6c341 (patch)
treefafdcf116102866fa29ebefa2c35ee86fda9a26b
parentAdd a configured separator for the in file seed info. (diff)
downloadgentoo-keys-5d2a88b991ac9bf93462e6b17c6abebadda6c341.tar.gz
gentoo-keys-5d2a88b991ac9bf93462e6b17c6abebadda6c341.tar.bz2
gentoo-keys-5d2a88b991ac9bf93462e6b17c6abebadda6c341.zip
Initial commit of an ldap search and seed file creation tool.
This app is intended to be run on infra machines or a dev's home directory on dev.gentoo.org in order for it to have access to the gentoo ldap server.
-rwxr-xr-xbin/ldap-seeds51
-rw-r--r--gkeyldap/__init__.py1
-rw-r--r--gkeyldap/cli.py215
-rw-r--r--gkeyldap/search.py111
-rw-r--r--gkeys/cli.py12
-rw-r--r--testpath4
6 files changed, 390 insertions, 4 deletions
diff --git a/bin/ldap-seeds b/bin/ldap-seeds
new file mode 100755
index 0000000..c40bd48
--- /dev/null
+++ b/bin/ldap-seeds
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+'''Gentoo-keys is a gpg key manager for managing
+ gentoo's gpg-signing keys. It is these keys that are
+ used to verify and validate release media, etc..
+
+ Distributed under the terms of the GNU General Public License v2
+
+ Copyright:
+ (c) 2011 Brian Dolbec
+ Distributed under the terms of the GNU General Public License v2
+
+ Author(s):
+ Brian Dolbec <dolsen@gentoo.org>
+
+'''
+
+from __future__ import print_function
+
+import os
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+ import signal
+
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ print()
+ sys.exit(1)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+except KeyboardInterrupt:
+ print()
+ sys.exit(1)
+
+
+from gkeyldap.cli import Main
+
+root = None
+try:
+ root = os.environ['ROOT']
+except KeyError:
+ pass
+
+main = Main(root=root)
+main()
diff --git a/gkeyldap/__init__.py b/gkeyldap/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gkeyldap/__init__.py
@@ -0,0 +1 @@
+
diff --git a/gkeyldap/cli.py b/gkeyldap/cli.py
new file mode 100644
index 0000000..f3c2ced
--- /dev/null
+++ b/gkeyldap/cli.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import ldap
+import sys
+import os
+import argparse
+
+from gkeys.log import logger
+from gkeys.config import GKeysConfig, GKEY
+from gkeys.seed import Seeds
+from gkeyldap.search import (LdapSearch, UID, CN, STATUS, GPGKEY,
+ MAIL, GPGFINGERPRINT, gkey2ldap_map, gkey2SEARCH)
+
+
+# set debug level to max
+logger.setLevel(1)
+
+
+class Main(object):
+ '''Main command line interface class'''
+
+
+ def __init__(self, root=None, config=None, print_results=True):
+ """ Main class init function.
+
+ @param root: string, root path to use
+ """
+ self.root = root or "/"
+ self.config = config or GKeysConfig(root=root)
+ self.print_results = print_results
+ self.args = None
+ self.seeds = None
+
+
+ def __call__(self, args=None):
+ logger.debug("Main:__call__()")
+ if args:
+ self.run(self.parse_args(args))
+ else:
+ self.run(self.parse_args(sys.argv[1:]))
+
+
+ def parse_args(self, args):
+ '''Parse a list of aruments
+
+ @param args: list
+ @returns argparse.Namespace object
+ '''
+ logger.debug('args: %s' % args)
+ actions = ['ldapsearch', 'updateseeds']
+ parser = argparse.ArgumentParser(
+ prog='gkeys',
+ description='Gentoo-keys manager program',
+ epilog='''Caution: adding untrusted keys to these keyrings can
+ be hazardous to your system!''')
+ # actions
+ parser.add_argument('action', choices=actions, nargs='?',
+ default='ldapsearch', help='Search ldap or update the seed file')
+ # options
+ parser.add_argument('-c', '--config', dest='config', default=None,
+ help='The path to an alternate config file')
+ parser.add_argument('-d', '--dest', dest='destination', default=None,
+ help='The destination db file path')
+ parser.add_argument('-N', '--name', dest='name', default=None,
+ help='The name to search for')
+ parser.add_argument('-n', '--nick', dest='nick', default=None,
+ help='The nick or user id (uid) to search for')
+ parser.add_argument('-m', '--mail', dest='mail', default=None,
+ help='The email address to search for')
+ parser.add_argument('-k', '--keyid', dest='keyid', default=None,
+ help='The gpg keyid to search for')
+ parser.add_argument('-f', '--fingerprint', dest='fingerprint', default=None,
+ help='The gpg fingerprint to search for')
+ parser.add_argument('-S', '--status', default=False,
+ help='The seedfile path to use')
+
+ return parser.parse_args(args)
+
+
+ def run(self, args):
+ '''Run the args passed in
+
+ @param args: list or argparse.Namespace object
+ '''
+ if not args:
+ logger.error("Main.run() invalid args argument passed in")
+ if isinstance(args, list):
+ args = self.parse_args(args)
+ if args.config:
+ logger.debug("Found alternate config request: %s" % args.config)
+ self.config.defaults['config'] = args.config
+ # now make it load the config file
+ self.config.read_config()
+
+ func = getattr(self, '_action_%s' % args.action)
+ logger.debug('Found action: %s' % args.action)
+ results = func(args)
+
+
+ def _action_ldapsearch(self, args):
+ l = LdapSearch()
+ if not l.connect():
+ print("Aborting Search...Connection failed")
+ return False
+ logging.debug("args = %s" % str(args))
+ x, target, search_field = self.get_args(args)
+ results = l.search(target, search_field)
+ devs = l.result2dict(results, gkey2ldap_map[x])
+ for dev in sorted(devs):
+ print(dev, devs[dev])
+ print("============================================")
+ print "Total number of devs in results:", len(devs)
+ return True
+
+
+ def _action_updateseeds(self, args):
+ l = LdapSearch()
+ if not l.connect():
+ print("Aborting Update...Connection failed")
+ return False
+ results = l.search('*', UID)
+ info = l.result2dict(results, 'uid')
+ logger.debug("_action_updateseeds, got results :) converted to info")
+ if not self.create_seedfile(info):
+ logger.error("Dev seed file update failure: "
+ "Original seed file is intact & untouched.")
+ old = self.config['dev-seedfile'] + '.old'
+ try:
+ if os.path.exists(old):
+ logger.debug("Removing 'old' seed file: %s" % old)
+ os.unlink(old)
+ if os.path.exists(self.config['dev-seedfile']):
+ logger.debug("Renaming current seed file to: %s" % old)
+ os.rename(self.config['dev-seedfile'], old)
+ logger.debug("Renaming 'new' seed file to: %s" % self.config['dev-seedfile'])
+ os.rename(self.config['dev-seedfile'] + '.new',
+ self.config['dev-seedfile'])
+ except IOError:
+ raise
+ print("Developer Seed file updated")
+ return True
+
+
+ def create_seedfile(self, devs):
+ logger.debug("create_seedfile, arrived")
+ filename = self.config['dev-seedfile'] + '.new'
+ self.seeds = Seeds(filename)
+ for dev in devs:
+ logger.debug("create_seedfile, dev = %s, %s" % (str(dev), str(devs[dev])))
+ new_gkey = GKEY._make(self.build_gkeylist(devs[dev]))
+ self.seeds.add(new_gkey)
+ logger.debug("create_seedfile, seeds created...saving file: %s" % filename)
+ return self.seeds.save()
+
+
+ @staticmethod
+ def get_args(args):
+ for x in ['nick', 'name', 'gpgkey', 'fingerprint', 'status']:
+ if x:
+ target = getattr(args, x)
+ search_field = gkey2SEARCH[x]
+ break
+ return (x, target, search_field)
+
+
+
+ @staticmethod
+ def build_gkeydict(info):
+ keyinfo = {}
+ for x in GKEY._fields:
+ field = gkey2ldap_map[x]
+ if not field:
+ continue
+ try:
+ values = info[field]
+ if values and values in ['uid' ]:
+ value = values[0]
+ else:
+ value = values
+ if value:
+ keyinfo[x] = value
+ except KeyError:
+ pass
+ return keyinfo
+
+
+ @staticmethod
+ def build_gkeylist(info):
+ keyinfo = []
+ logger.debug("build_gkeylist, info = %s" % str(info))
+ for x in GKEY._fields:
+ field = gkey2ldap_map[x]
+ if not field:
+ keyinfo.append(None)
+ continue
+ try:
+ values = info[field]
+ if values and field in ['uid', 'name' ]:
+ value = values[0]
+ else:
+ value = values
+ keyinfo.append(value)
+ except KeyError:
+ keyinfo.append(None)
+ return keyinfo
+
+
+if __name__ == '__main__':
+
+ Main()
+
+
+
diff --git a/gkeyldap/search.py b/gkeyldap/search.py
new file mode 100644
index 0000000..f432dcf
--- /dev/null
+++ b/gkeyldap/search.py
@@ -0,0 +1,111 @@
+import ldap
+import sys
+
+from gkeys.log import logger
+from gkeys.config import GKEY
+
+
+# set debug level to max
+logger.setLevel(1)
+
+
+default_server = 'ldap://ldap1.gentoo.org'
+# add uid to the results so you don't have to
+# separate it out of the results tuple[0] value
+default_fields = ['uid', 'cn', 'mail', 'gentooStatus', 'gpgkey', 'gpgfingerprint']
+default_criteria = 'ou=devs,dc=gentoo,dc=org'
+
+# establish a ldap fields to GKEY._fields map
+gkey2ldap_map = {
+ 'nick': 'uid',
+ 'name': 'cn',
+ 'keyid': 'gpgkey',
+ 'longkeyid': '',
+ 'keyring': '',
+ 'fingerprint': 'gpgfingerprint'
+}
+# Sanity check they are in sync
+if not sorted(gkey2ldap_map) == sorted(GKEY._fields):
+ raise "Search.py out of sync with GKEY class"
+
+
+# Now for some search field defaults
+UID = '(uid=%s)'
+CN = '(cn=%s)'
+STATUS = '(gentooStatus=%s)'
+GPGKEY = '(gpgkey=%s)'
+MAIL = '(mail=%s)'
+GPGFINGERPRINT = '(gpgfingerprint=%s)'
+
+gkey2SEARCH = {
+ 'nick': UID,
+ 'name': CN,
+ 'status': STATUS,
+ 'keyid': GPGKEY,
+ 'mail': MAIL,
+ 'fingerprint': GPGFINGERPRINT,
+}
+
+
+class LdapSearch(object):
+ '''Class to perform searches on the configured ldap server
+ '''
+
+ def __init__(self, server=None, fields=None, criteria=None):
+ self.server = server or default_server
+ self.fields = fields or default_fields
+ self.criteria = criteria or default_criteria
+ logger.debug('LdapSearch: __init__; server...: %s' % self.server)
+ logger.debug('LdapSearch: __init__; fields...: %s' % self.fields)
+ logger.debug('LdapSearch: __init__; criteria.: %s' % self.criteria)
+ self.ldap_connection = None
+
+
+ def connect(self, server=None,):
+ '''Creates our ldap server connection
+
+ '''
+ if server:
+ self.server = server
+ logger.debug('LdapSearch: connect; new server: %s' % self.server)
+ try:
+ self.ldap_connection = ldap.initialize(self.server)
+ self.ldap_connection.set_option(ldap.OPT_X_TLS_DEMAND, True)
+ self.ldap_connection.start_tls_s()
+ self.ldap_connection.simple_bind_s()
+ except Exception as e:
+ logger.error('LdapSearch: connect; failed to connect ot server: %s' % self.server)
+ logger.error("Exception was: %s" % str(e))
+ return False
+ logger.debug('LdapSearch: connect; connection: %s' % self.ldap_connection)
+ return True
+
+
+
+ def search(self, target, search_field=UID, fields=None, criteria=None):
+ '''Perform the ldap search
+ '''
+ if not target:
+ logger.debug('LdapSearch: search; invalid target: "%s"' % target)
+ return {}
+ if not fields:
+ fields = self.fields
+ else:
+ logger.debug('LdapSearch: search; new fields: %s' % str(fields))
+ if not criteria:
+ criteria = self.criteria
+ else:
+ logger.debug('LdapSearch: search; new criteria: %s' % criteria)
+ results = self.ldap_connection.search_s(criteria,
+ ldap.SCOPE_ONELEVEL, search_field % target, fields)
+ #logger.debug('LdapSearch: search; result = %s' % str(results))
+ return results
+
+
+ def result2dict(self, results, key='uid'):
+ _dict = {}
+ for entry in results:
+ info = entry[1]
+ key_value = info[key][0]
+ _dict[key_value] = info
+ return _dict
diff --git a/gkeys/cli.py b/gkeys/cli.py
index f9720f9..133a14f 100644
--- a/gkeys/cli.py
+++ b/gkeys/cli.py
@@ -110,6 +110,10 @@ class Main(object):
func = getattr(self, '_action_%s' % args.action)
logger.debug('Found action: %s' % args.action)
results = func(args)
+ if not results:
+ print("No results found. Check your configuration and that the",
+ "seed file exists.")
+ return
# super simple output for the time being
if self.print_results:
print('\n\nGkey results:')
@@ -142,6 +146,8 @@ class Main(object):
def _load_seeds(self, filename):
+ if not filename:
+ return None
filepath = self.config.get_key(filename + "-seedfile")
logger.debug("_load_seeds(); seeds filepath to load: "
"%s" % filepath)
@@ -155,8 +161,10 @@ class Main(object):
kwargs = self.build_gkeydict(args)
logger.debug("_action_listseed(); kwargs: %s" % str(kwargs))
seeds = self._load_seeds(args.seeds)
- results = seeds.list(**kwargs)
- return results
+ if seeds:
+ results = seeds.list(**kwargs)
+ return results
+ return None
def _action_addseed(self, args):
diff --git a/testpath b/testpath
index ed569d0..a9da312 100644
--- a/testpath
+++ b/testpath
@@ -12,6 +12,6 @@
# $ esearch some-package
-export PATH="$(dirname $BASH_SOURCE[0])../pyGPG/bin:$(dirname $BASH_SOURCE[0])/bin:${PATH}"
+export PATH="$(dirname $BASH_SOURCE[0])/../pyGPG/bin:$(dirname $BASH_SOURCE[0])/bin:${PATH}"
-export PYTHONPATH="$(dirname $BASH_SOURCE[0])../pyGPG/:$(dirname $BASH_SOURCE[0])/:${PYTHONPATH}"
+export PYTHONPATH="$(dirname $BASH_SOURCE[0])/../pyGPG/:$(dirname $BASH_SOURCE[0])/:${PYTHONPATH}"