aboutsummaryrefslogtreecommitdiffstats
path: root/RepSys/plugins
diff options
context:
space:
mode:
authorNicolas Vigier <boklm@mageia.org>2011-01-04 16:15:53 +0000
committerNicolas Vigier <boklm@mageia.org>2011-01-04 16:15:53 +0000
commit88a840788e82289d417983acf4b49f2c2778296d (patch)
tree2a73dbdb181d05fc5417dbc75baf6fa0a4c73ccb /RepSys/plugins
downloadmgarepo-88a840788e82289d417983acf4b49f2c2778296d.tar
mgarepo-88a840788e82289d417983acf4b49f2c2778296d.tar.gz
mgarepo-88a840788e82289d417983acf4b49f2c2778296d.tar.bz2
mgarepo-88a840788e82289d417983acf4b49f2c2778296d.tar.xz
mgarepo-88a840788e82289d417983acf4b49f2c2778296d.zip
fix problem with python threads on 2010.1
Diffstat (limited to 'RepSys/plugins')
-rw-r--r--RepSys/plugins/__init__.py27
-rw-r--r--RepSys/plugins/ldapusers.py189
-rw-r--r--RepSys/plugins/sample.py.txt14
3 files changed, 230 insertions, 0 deletions
diff --git a/RepSys/plugins/__init__.py b/RepSys/plugins/__init__.py
new file mode 100644
index 0000000..e4f4e08
--- /dev/null
+++ b/RepSys/plugins/__init__.py
@@ -0,0 +1,27 @@
+import os
+
+loaded = {}
+
+def load():
+ # based on smart's plugin system
+ pluginsdir = os.path.dirname(__file__)
+ for entry in os.listdir(pluginsdir):
+ if entry != "__init__.py" and entry.endswith(".py"):
+ name = entry[:-3]
+ loaded[name] = __import__("RepSys.plugins."+name, {}, {},
+ [name])
+ elif os.path.isdir(entry):
+ initfile = os.path.join(entry, "__init__.py")
+ if os.path.isfile(initfile):
+ loaded[entry] = __import__("RepSys.plugins."+entry, {}, {},
+ [entry])
+
+def list():
+ return loaded.keys()
+
+def help(name):
+ from RepSys import Error
+ try:
+ return loaded[name].__doc__
+ except KeyError:
+ raise Error, "plugin %s not found" % name
diff --git a/RepSys/plugins/ldapusers.py b/RepSys/plugins/ldapusers.py
new file mode 100644
index 0000000..e56371d
--- /dev/null
+++ b/RepSys/plugins/ldapusers.py
@@ -0,0 +1,189 @@
+"""
+A Repsys plugin for obtaining users from a LDAP server.
+
+In order to enable the plugin, the user must define the following
+options in the [global] section of repsys.conf:
+
+ ldap-uri [required if ldap-server is unset]
+ the URI of the server, you can refer to more than one server by
+ adding more URIs separated by spaces::
+
+ ldap-uri = ldap://ldap.network/ ldaps://backup.network:22389/
+
+ ldap-server [required if ldap-uri is unset]
+ the host name of the LDAP server
+ ldap-port [optional] [default: 389]
+ the port of the LDAP server
+ ldap-base [required]
+ the base DN where the search will be performed
+ ldap-binddn [optional] [default: empty]
+ the DN used to bind
+ ldap-bindpw [optional] [default: empty]
+ the password used to bind
+ ldap-starttls [optional] [default: no]
+ use "yes" or "no" to enable or disable the use of the STARTTLS
+ LDAP extension
+ ldap-filterformat [optional]
+ [default: (&(objectClass=inetOrgPerson)(uid=$username))]
+ RFC-2254 filter string used in the search of the user entry.
+ Note that this is a python template string and will have the
+ user name as parameter. For example:
+
+ ldap-filterformat = (&(objectClass=inetOrgPerson)(uid=$username))
+
+ Will result in the search filter:
+
+ (&(objectClass=inetOrgPerson)(uid=john))
+
+ ldap-resultformat [optional] [default: $cn <$mail>]
+ This is a python template string. This string will be
+ formatted using one dict object containing the fields
+ returned in the LDAP search, for example:
+
+ >>> format = Template("$cn <$mail>")
+ >>> d = search(basedn, filter)
+ >>> d
+ {"cn": "John Doe", "mail": "john@mandriva.org",
+ "uidNumber": "1290", "loginShell": "/bin/bash",
+ ... many other attributes ... }
+ >>> value = format.substitute(d)
+ >>> print value
+ John Doe <john@mandriva.org>
+
+ Note that only the first value of the attributes will be
+ used.
+
+When the searched option is not found, it will try in repsys.conf. All
+the values found. (including from repsys.conf) will be cached between
+each configuration access.
+
+This plugin requires the package python-ldap.
+
+For more information, look http://qa.mandriva.com/show_bug.cgi?id=30549
+"""
+from RepSys import Error, config
+
+import string
+
+users_cache = {}
+
+class LDAPError(Error):
+ def __init__(self, ldaperr):
+ self.ldaperr = ldaperr
+ name = ldaperr.__class__.__name__
+ desc = ldaperr.message["desc"]
+ self.message = "LDAP error %s: %s" % (name, desc)
+ self.args = self.message,
+
+def strip_entry(entry):
+ "Leave only the first value in all keys in the entry"
+ new = dict((key, value[0]) for key, value in entry.iteritems())
+ return new
+
+def interpolate(optname, format, data):
+ tmpl = string.Template(format)
+ try:
+ return tmpl.substitute(data)
+ except KeyError, e:
+ raise Error, "the key %s was not found in LDAP search, " \
+ "check your %s configuration" % (e, optname)
+ except (TypeError, ValueError), e:
+ raise Error, "LDAP response formatting error: %s. Check " \
+ "your %s configuration" % (e, optname)
+
+def used_attributes(format):
+ class DummyDict:
+ def __init__(self):
+ self.found = []
+ def __getitem__(self, key):
+ self.found.append(key)
+ return key
+ dd = DummyDict()
+ t = string.Template(format)
+ t.safe_substitute(dd)
+ return dd.found
+
+def make_handler():
+ uri = config.get("global", "ldap-uri")
+ if not uri:
+ server = config.get("global", "ldap-server")
+ if not server:
+ # ldap support is not enabled if ldap-uri nor ldap-server are
+ # defined
+ def dummy_wrapper(section, option=None, default=None, walk=False):
+ return config.get(section, option, default, wrap=False)
+ return dummy_wrapper
+
+ try:
+ port = int(config.get("global", "ldap-port", 389))
+ except ValueError:
+ raise Error, "the option ldap-port requires an integer, please "\
+ "check your configuration files"
+ uri = "ldap://%s:%d" % (server, port)
+
+ basedn = config.get("global", "ldap-base")
+ binddn = config.get("global", "ldap-binddn")
+ bindpw = config.get("global", "ldap-bindpw", "")
+ filterformat = config.get("global", "ldap-filterformat",
+ "(&(objectClass=inetOrgPerson)(uid=$username))", raw=1)
+ format = config.get("global", "ldap-resultformat", "$cn <$mail>", raw=1)
+
+ valid = {"yes": True, "no": False}
+ raw = config.get("global", "ldap-starttls", "no")
+ try:
+ starttls = valid[raw]
+ except KeyError:
+ raise Error, "invalid value %r for ldap-starttls, use "\
+ "'yes' or 'no'" % raw
+
+ try:
+ import ldap
+ except ImportError:
+ raise Error, "LDAP support needs the python-ldap package "\
+ "to be installed"
+ else:
+ from ldap.filter import escape_filter_chars
+
+ def users_wrapper(section, option=None, default=None, walk=False):
+ global users_cache
+ if walk:
+ raise Error, "ldapusers plugin does not support user listing"
+ assert option is not None, \
+ "When not section walking, option is required"
+
+ value = users_cache.get(option)
+ if value is not None:
+ return value
+
+ try:
+ l = ldap.initialize(uri)
+ if starttls:
+ l.start_tls_s()
+ if binddn:
+ l.bind(binddn, bindpw)
+ except ldap.LDAPError, e:
+ raise LDAPError(e)
+ try:
+ data = {"username": escape_filter_chars(option)}
+ filter = interpolate("ldap-filterformat", filterformat, data)
+ attrs = used_attributes(format)
+ try:
+ found = l.search_s(basedn, ldap.SCOPE_SUBTREE, filter,
+ attrlist=attrs)
+ except ldap.LDAPError, e:
+ raise LDAPError(e)
+ if found:
+ dn, entry = found[0]
+ entry = strip_entry(entry)
+ value = interpolate("ldap-resultformat", format, entry)
+ else:
+ # issue a warning?
+ value = config.get(section, option, default, wrap=False)
+ users_cache[option] = value
+ return value
+ finally:
+ l.unbind_s()
+
+ return users_wrapper
+
+config.wrap("users", handler=make_handler())
diff --git a/RepSys/plugins/sample.py.txt b/RepSys/plugins/sample.py.txt
new file mode 100644
index 0000000..9877f3c
--- /dev/null
+++ b/RepSys/plugins/sample.py.txt
@@ -0,0 +1,14 @@
+# Sample repsys plugin. In order to test it, rename to sample.py
+# vim:ft=python
+from RepSys import config
+
+def users_wrapper(section, option=None, default=None, walk=False):
+ d = {"foolano": "Foolano De Tal <foolano@bla.com>",
+ "ceeclano": "Ceeclano Algumacoisa <ceeclano@bli.com>",
+ "beltrano": "Beltrano Bla <beltrano@mail.ru>"}
+ if walk:
+ return d.items()
+
+ return d.get(option, default)
+
+config.wrap("users", handler=users_wrapper)