source: soft/build_system/build_system/repsys/tags/V1_6_17/RepSys/plugins/ldapusers.py @ 1

Last change on this file since 1 was 1, checked in by fasma, 12 years ago

Initial Import from Mandriva's soft revision 224062 and package revision 45733

File size: 5.6 KB
Line 
1"""
2A Repsys plugin for obtaining users from a LDAP server.
3
4In order to enable the plugin, the user must define the following
5options in the [global] section of repsys.conf:
6
7    ldap-server [required]
8        the host name of the LDAP server
9    ldap-port [optional] [default: 389]
10        the port of the LDAP server
11    ldap-base [required]
12        the base DN where the search will be performed
13    ldap-binddn [optional] [default: empty]
14        the DN used to bind
15    ldap-bindpw [optional] [default: empty]
16        the password used to bind
17    ldap-filterformat [optional]
18            [default: (&(objectClass=inetOrgPerson)(uid=$username))]
19        RFC-2254 filter string used in the search of the user entry.
20        Note that this is a python template string and will have the
21        user name as parameter. For example:
22
23           ldap-filterformat = (&(objectClass=inetOrgPerson)(uid=$username))
24
25        Will result in the search filter:
26
27           (&(objectClass=inetOrgPerson)(uid=john))
28
29    ldap-resultformat [optional] [default: $cn <$mail>]
30        This is a python template string. This string will be
31        formatted using one dict object containing the fields
32        returned in the LDAP search, for example:
33
34          >>> format = Template("$cn <$mail>")
35          >>> d = search(basedn, filter)
36          >>> d
37          {"cn": "John Doe", "mail": "john@mandriva.org",
38           "uidNumber": "1290", "loginShell": "/bin/bash",
39            ... many other attributes ... }
40          >>> value = format.substitute(d)
41          >>> print value
42          John Doe <john@mandriva.org>
43
44        Note that only the first value of the attributes will be
45        used.
46
47When the searched option is not found, it will try in repsys.conf. All
48the values found.  (including from repsys.conf) will be cached between
49each configuration access.
50
51This plugin requires the package python-ldap.
52
53For more information, look http://qa.mandriva.com/show_bug.cgi?id=30549
54"""
55from RepSys import Error, config
56
57import string
58
59users_cache = {}
60
61class LDAPError(Error):
62    def __init__(self, ldaperr):
63        self.ldaperr = ldaperr
64        name = ldaperr.__class__.__name__
65        desc = ldaperr.message["desc"]
66        self.message = "LDAP error %s: %s" % (name, desc)
67        self.args = self.message,
68
69def strip_entry(entry):
70    "Leave only the first value in all keys in the entry"
71    new = dict((key, value[0]) for key, value in entry.iteritems())
72    return new
73
74def interpolate(optname, format, data):
75    tmpl = string.Template(format)
76    try:
77        return tmpl.substitute(data)
78    except KeyError, e:
79        raise Error, "the key %s was not found in LDAP search, " \
80                "check your %s configuration" % (e, optname)
81    except (TypeError, ValueError), e:
82        raise Error, "LDAP response formatting error: %s. Check " \
83                "your %s configuration" % (e, optname)
84
85def used_attributes(format):
86    class DummyDict:
87        def __init__(self):
88            self.found = []
89        def __getitem__(self, key):
90            self.found.append(key)
91            return key
92    dd = DummyDict()
93    t = string.Template(format)
94    t.safe_substitute(dd)
95    return dd.found
96
97def make_handler():
98    server = config.get("global", "ldap-server")
99    try:
100        port = int(config.get("global", "ldap-port", 389))
101    except ValueError:
102        raise Error, "the option ldap-port requires an integer, please "\
103                "check your configuration files"
104    basedn = config.get("global", "ldap-base")
105    binddn = config.get("global", "ldap-binddn")
106    bindpw = config.get("global", "ldap-bindpw", "")
107    filterformat = config.get("global", "ldap-filterformat",
108            "(&(objectClass=inetOrgPerson)(uid=$username))", raw=1)
109    format = config.get("global", "ldap-resultformat", "$cn <$mail>", raw=1)
110
111    if server is None:
112        def dummy_wrapper(section, option=None, default=None, walk=False):
113            return config.get(section, option, default, wrap=False)
114        return dummy_wrapper
115
116    try:
117        import ldap
118    except ImportError:
119        raise Error, "LDAP support needs the python-ldap package "\
120                "to be installed"
121    else:
122        from ldap.filter import escape_filter_chars
123
124    def users_wrapper(section, option=None, default=None, walk=False):
125        global users_cache
126        if walk:
127            raise Error, "ldapusers plugin does not support user listing"
128        assert option is not None, \
129                "When not section walking, option is required"
130
131        value = users_cache.get(option)
132        if value is not None:
133            return value
134
135        try:
136            l = ldap.open(server, port)
137            if binddn:
138                l.bind(binddn, bindpw)
139        except ldap.LDAPError, e:
140            raise LDAPError(e)
141        try:
142            data = {"username": escape_filter_chars(option)}
143            filter = interpolate("ldap-filterformat", filterformat, data)
144            attrs = used_attributes(format)
145            try:
146                found = l.search_s(basedn, ldap.SCOPE_SUBTREE, filter,
147                        attrlist=attrs)
148            except ldap.LDAPError, e:
149                raise LDAPError(e)
150            if found:
151                dn, entry = found[0]
152                entry = strip_entry(entry)
153                value = interpolate("ldap-resultformat", format, entry)
154            else:
155                # issue a warning?
156                value = config.get(section, option, default, wrap=False)
157            users_cache[option] = value
158            return value
159        finally:
160            l.unbind_s()
161
162    return users_wrapper
163
164config.wrap("users", handler=make_handler())
Note: See TracBrowser for help on using the repository browser.