Attachment 'ldap_groups.patch'

Download

   1 diff -r a8a777074233 MoinMoin/auth/ldap_login.py
   2 --- a/MoinMoin/auth/ldap_login.py	Mon Jul 27 01:55:59 2009 +0200
   3 +++ b/MoinMoin/auth/ldap_login.py	Wed Jul 29 14:53:47 2009 +0200
   4 @@ -229,6 +229,7 @@
   5                  else:
   6                      u = user.User(request, auth_username=username, auth_method=self.name, auth_attribs=('name', 'password', 'mailto_author', ))
   7                  u.name = username
   8 +                u.dn = dn
   9                  u.aliasname = aliasname
  10                  u.remember_me = 0 # 0 enforces cookie_lifetime config param
  11                  logging.debug("creating userprefs with name %r email %r alias %r" % (username, email, aliasname))
  12 diff -r a8a777074233 MoinMoin/datastruct/backends/ldap_groups.py
  13 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
  14 +++ b/MoinMoin/datastruct/backends/ldap_groups.py	Wed Jul 29 14:53:47 2009 +0200
  15 @@ -0,0 +1,87 @@
  16 +# -*- coding: iso-8859-1 -*-
  17 +"""
  18 +    MoinMoin - ldap group lazy backend.
  19 +
  20 +    The ldap group backend allows one to define groups in an
  21 +    ldap server. Group members can must be authenticated via
  22 +    ldap. 
  23 +
  24 +    @copyright: 2009 Benoit Peccatte(peck)
  25 +    @license: GPL, see COPYING for details
  26 +"""
  27 +
  28 +from MoinMoin import log
  29 +logging = log.getLogger(__name__)
  30 +
  31 +from MoinMoin.datastruct.backends import LazyGroup, LazyGroupsBackend
  32 +from MoinMoin.util.ldap_connection import LDAPConnection
  33 +import ldap
  34 +from MoinMoin.user import User
  35 +
  36 +class LdapGroup(LazyGroup):
  37 +    pass
  38 +
  39 +
  40 +class LdapGroups(LazyGroupsBackend):
  41 +
  42 +    def __init__(self, request, 
  43 +        ldap_connection,           # LDAPConnection to use for connections
  44 +        base_dn='',                # base ldap dn to use when searching for groups
  45 +        scope=ldap.SCOPE_SUBTREE,  # scope of the search 
  46 +        filter='',                 # filter to use when searching for groups 
  47 +        member_attribute='member', # attribute name for group members
  48 +        name_attribute='cn',       # attribute name for group name
  49 +        ):
  50 +        
  51 +        super(LdapGroups, self).__init__(request)
  52 +        self.base = base_dn
  53 +        self.scope = scope
  54 +        if(filter != '' and filter[0] != '('):
  55 +            filter = '(' + filter + ')'
  56 +        self.filter = filter
  57 +        self.member_attribute = member_attribute
  58 +        self.name_attribute = name_attribute
  59 +        self.ldap = ldap_connection
  60 +
  61 +    def __contains__(self, group_name):
  62 +        filter = self._getfilter(group_name)
  63 +        res = self.ldap.search_single(self.base, self.scope, filter, 'dn')
  64 +        return res != []
  65 +
  66 +    def __iter__(self):
  67 +        filter = self._getfilter('*')
  68 +        return self.ldap.search_single(self.base, self.scope, filter, 'dn')
  69 +
  70 +    def __getitem__(self, group_name):
  71 +        return LdapGroup(self.request, group_name, self)
  72 +
  73 +    def _iter_group_members(self, group_name):
  74 +        filter = self._getfilter(group_name)
  75 +        return self.ldap.search_single( self.base, self.scope, filter, self.member_attribute)
  76 +
  77 +    def _group_has_member(self, group_name, member):
  78 +        # only check users that are authenticated using ldap
  79 +        u = User(self.request, auth_username=member)
  80 +        if not hasattr(u,'dn'):
  81 +            return False
  82 +        filter = self._getfilter(group_name, u.dn)
  83 +        res = self.ldap.search_single( self.base, self.scope, filter, 'dn')
  84 +        return res != []
  85 +
  86 +    def _getfilter(self, group_name, member=None):
  87 +        """ Create a filter string for a group. 
  88 +            Add a member filter if one is provided."""
  89 +        # extract real group name from the form XxxGroup
  90 +        grp = self.page_group_regex.search(group_name)
  91 +        if(grp == None):
  92 +            return False
  93 +        group = grp.group(2)
  94 +        
  95 +        filter = '(' + self.name_attribute + '=' + group + ')'
  96 +        if(self.filter != ''):
  97 +            filter = '(&' + self.filter + filter + ')'
  98 +        
  99 +        if member == None:
 100 +            return filter
 101 +        return '(&' + filter + '(' + self.member_attribute + '=' + member + '))'
 102 +
 103 diff -r a8a777074233 MoinMoin/util/ldap_connection.py
 104 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 105 +++ b/MoinMoin/util/ldap_connection.py	Wed Jul 29 14:53:47 2009 +0200
 106 @@ -0,0 +1,133 @@
 107 +# -*- coding: iso-8859-1 -*-
 108 +"""
 109 +    MoinMoin - ldap connection object
 110 +
 111 +    The connexion object holds informations to connect to a single 
 112 +    ldap server.
 113 +
 114 +    @copyright: 2009 Benoit Peccatte(peck)
 115 +    @license: GPL, see COPYING for details
 116 +"""
 117 +
 118 +from MoinMoin import log
 119 +logging = log.getLogger(__name__)
 120 +
 121 +try:
 122 +    import ldap
 123 +except ImportError, err:
 124 +    logging.error("You need to have python-ldap installed (%s)." % str(err))
 125 +    raise
 126 +
 127 +class LDAPConnection:
 128 +    def __init__(self, 
 129 +        server_uri='ldap://localhost',  # ldap / active directory server URI
 130 +                                        # use ldaps://server:636 url for ldaps,
 131 +                                        # use  ldap://server for ldap without tls (and set start_tls to 0),
 132 +                                        # use  ldap://server for ldap with tls (and set start_tls to 1 or 2).
 133 +        bind_dn='',  # We can only use fixed user and password here
 134 +                     # TODO implement "the username and password we got from the user" in ldap_auth
 135 +        bind_pw='',
 136 +        referrals=0, # LDAP REFERRALS (0 needed for AD)
 137 +        coding='utf-8', # coding used for ldap queries and result values
 138 +        timeout=10, # how long we wait for the ldap server [s]
 139 +        start_tls=0, # 0 = No, 1 = Try, 2 = Required
 140 +        tls_cacertdir=None,
 141 +        tls_cacertfile=None,
 142 +        tls_certfile=None,
 143 +        tls_keyfile=None,
 144 +        tls_require_cert=0, # 0 == ldap.OPT_X_TLS_NEVER (needed for self-signed certs)
 145 +        ):
 146 +
 147 +        self.server_uri = server_uri
 148 +        self.bind_dn = bind_dn
 149 +        self.bind_pw = bind_pw
 150 +        self.referrals = referrals
 151 +        self.coding = coding
 152 +        self.timeout = timeout
 153 +        self.start_tls = start_tls
 154 +        self.tls_cacertdir = tls_cacertdir
 155 +        self.tls_cacertfile = tls_cacertfile
 156 +        self.tls_certfile = tls_certfile
 157 +        self.tls_keyfile = tls_keyfile
 158 +        self.tls_require_cert = tls_require_cert
 159 +
 160 +        self.ldap = None
 161 +
 162 +    def __connect(self):
 163 +        """ Make a new connection to ldap only if needed.
 164 +            Public method should call this."""
 165 +        if (self.ldap != None):
 166 +            return 
 167 +        self.ldap = self.__new_ldap(self.bind_dn, self.bind_pw)
 168 +
 169 +    def __new_ldap(self, binddn, password):
 170 +        """ Create a connection object and bind. """
 171 +        try:
 172 +            # options
 173 +            logging.debug("Setting misc. ldap options...")
 174 +            ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)
 175 +            ldap.set_option(ldap.OPT_REFERRALS, self.referrals)
 176 +            ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout)
 177 +            if hasattr(ldap, 'TLS_AVAIL') and ldap.TLS_AVAIL:
 178 +                for option, value in (
 179 +                    (ldap.OPT_X_TLS_CACERTDIR, self.tls_cacertdir),
 180 +                    (ldap.OPT_X_TLS_CACERTFILE, self.tls_cacertfile),
 181 +                    (ldap.OPT_X_TLS_CERTFILE, self.tls_certfile),
 182 +                    (ldap.OPT_X_TLS_KEYFILE, self.tls_keyfile),
 183 +                    (ldap.OPT_X_TLS_REQUIRE_CERT, self.tls_require_cert),
 184 +                    (ldap.OPT_X_TLS, self.start_tls),
 185 +                    #(ldap.OPT_X_TLS_ALLOW, 1),
 186 +                ):
 187 +                    if value is not None:
 188 +                        ldap.set_option(option, value)
 189 +
 190 +            # connect and bind
 191 +            logging.debug("Trying to initialize %r." % self.server_uri)
 192 +            l = ldap.initialize(self.server_uri)
 193 +            l.protocol_version = ldap.VERSION3 # recommended by documentation
 194 +            logging.debug("Connected to LDAP server %r." % self.server_uri)
 195 +            if self.start_tls and server.startswith('ldap:'):
 196 +                logging.debug("Trying to start TLS to %r." % self.server_uri)
 197 +                try:
 198 +                    l.start_tls_s()
 199 +                    logging.debug("Using TLS to %r." % self.server_uri)
 200 +                except (ldap.SERVER_DOWN, ldap.CONNECT_ERROR), err:
 201 +                    logging.warning("Couldn't establish TLS to %r (err: %s)." % (self.server_uri, str(err)))
 202 +                    raise
 203 +
 204 +            l.simple_bind_s(binddn.encode(self.coding), password.encode(self.coding))
 205 +            logging.debug("Bound with binddn %r" % binddn)
 206 +            return l
 207 +        except ldap.LDAPError, error_message:
 208 +            print "LDAP error %r" % error_message
 209 +            raise
 210 +
 211 +    def authenticate(self, binddn, passwd):
 212 +        # TODO for ldap_auth.py
 213 +        return
 214 +
 215 +    def search(self, base, scope, filter, attributes):
 216 +        """ Make a specific search on the ldap server """
 217 +        self.__connect() 
 218 +        try:
 219 +            result_id = self.ldap.search(base.encode(self.coding), 
 220 +                                         scope, 
 221 +                                         filter.encode(self.coding),
 222 +                                         attributes)
 223 +            result_type, result_data = self.ldap.result(result_id, self.timeout)
 224 +            if result_type == ldap.RES_SEARCH_RESULT:
 225 +                return result_data
 226 +            else:
 227 +                print "unknown result_type"
 228 +        except ldap.LDAPError, error_message:
 229 +            print "search error %s" % error_message
 230 +
 231 +    def search_single(self, base, scope, filter, attribute):
 232 +        """ Search for a single attribute, returns an array of single values. """
 233 +        res = self.search(base, scope, filter, [attribute])
 234 +        if(attribute == 'dn'):
 235 +            first = lambda x: x[0]
 236 +        else:
 237 +            first = lambda x: x[1][attribute][0]
 238 +        return map(first, res)
 239 +
 240 

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2009-07-29 18:30:46, 9.9 KB) [[attachment:ldap_group2.patch]]
  • [get | view] (2009-07-30 14:21:47, 17.9 KB) [[attachment:ldap_group3.patch]]
  • [get | view] (2009-08-03 09:47:19, 18.0 KB) [[attachment:ldap_group4.patch]]
  • [get | view] (2009-07-29 13:42:43, 9.6 KB) [[attachment:ldap_groups.patch]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.