aboutsummaryrefslogtreecommitdiff
path: root/linaro_ldap.py
diff options
context:
space:
mode:
authorMatt Hart <matthew.hart@linaro.org>2015-06-14 20:21:18 +0100
committerMatt Hart <matthew.hart@linaro.org>2015-06-25 16:17:41 +0100
commitde9753cbbcd031cf9c654374d41bfd10cbc7392d (patch)
treeb58cc07d63245ad6dd90c0d4b282f7084078b1b3 /linaro_ldap.py
parenta2046fa8256863c97dee78c6ccc39d764adf42db (diff)
Use a library for accessing LDAP for ssh keys etc
Wrapper for the python LDAP library which uses config from local ldap.conf or override LDAP_CONF in the environment Command line credentials are now ignored. grok-slave-keys: use the linaro_ldap library to greatly simplify the script gitolite-tools/gitolite-keys: use the linaro_ldap library, remove logging and config parsing for simplicity Change-Id: I002efbc1f7d47d3120855038aa1c5cc3d8292c98
Diffstat (limited to 'linaro_ldap.py')
-rw-r--r--linaro_ldap.py88
1 files changed, 88 insertions, 0 deletions
diff --git a/linaro_ldap.py b/linaro_ldap.py
new file mode 100644
index 0000000..4a5be6e
--- /dev/null
+++ b/linaro_ldap.py
@@ -0,0 +1,88 @@
+import contextlib
+import os
+import subprocess
+import tempfile
+import ldap
+
+
+# To provide alternative ldap bind credentials, override the LDAP_CONF
+# environment variable when calling your script that makes use of the this
+# library
+LDAP_CONF = os.environ.get('LDAP_CONF', '/etc/ldap.conf')
+
+
+@contextlib.contextmanager
+def ldap_client(config):
+ client = ldap.initialize(config["uri"], trace_level=0)
+ client.set_option(ldap.OPT_REFERRALS, 0)
+ client.simple_bind(config["binddn"], config["bindpw"])
+ try:
+ yield client
+ finally:
+ client.unbind()
+
+
+def build_config():
+ config = {}
+ with open(LDAP_CONF) as f:
+ for line in f:
+ if line.startswith('binddn'):
+ if "binddn" not in config:
+ config["binddn"] = line.split(' ', 1)[1].strip()
+ elif line.startswith('bindpw'):
+ if "bindpw" not in config:
+ config["bindpw"] = line.split(' ', 1)[1].strip()
+ elif line.startswith('base'):
+ if "basedn" not in config:
+ config["basedn"] = line.split(' ', 1)[1].strip()
+ elif line.startswith('uri'):
+ if "uri" not in config:
+ config["uri"] = line.split(' ', 1)[1].strip()
+ return config
+
+
+def validate_key(pubkey):
+ with tempfile.NamedTemporaryFile(delete=True) as f:
+ f.write(pubkey)
+ f.flush()
+ try:
+ args = ['ssh-keygen', '-l', '-f', f.name]
+ subprocess.check_output(args, stderr=subprocess.PIPE)
+ except:
+ return False
+ return True
+
+
+def do_query(search_attr='uid', search_pat='*', attrlist=[]):
+ config = build_config()
+ with ldap_client(config) as client:
+ result = client.search_s(
+ config["basedn"],
+ ldap.SCOPE_SUBTREE,
+ '(%s=%s)' % (search_attr, search_pat),
+ attrlist)
+ return result
+
+
+def get_users_and_keys(only_validated=False):
+ """Gets all the users and their associated SSH key.
+ :return A list of tuples (uid, ssh_key), only if the user has an SSH
+ key.
+ """
+ result = do_query(attrlist=['uid', 'sshPublicKey'])
+ all_users = {}
+ for row in result:
+ try:
+ # Just pick the first UID, it does not really matter how the
+ # user is called, it will access the git repository via the
+ # 'git' user.
+ uid = row[1]['uid'][0]
+ ssh_keys = row[1]['sshPublicKey']
+ for index, ssh_key in enumerate(ssh_keys):
+ if not only_validated or validate_key(ssh_key):
+ key_name = '{0}@key_{1}.pub'.format(uid, index)
+ all_users.setdefault(uid, []).append((key_name, ssh_key))
+ except KeyError:
+ # If there are no SSH keys, skip this user.
+ pass
+ return all_users