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

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.