Attachment 'ldap_login_refactored.patch'

Download

   1 # HG changeset patch
   2 # User Thomas Waldmann <tw AT waldmann-edv DOT de>
   3 # Date 1204717258 -3600
   4 # Node ID 9d3f64f9daf49736ab8f6fa8f3efa71bc6c5bc10
   5 # Parent  6e28cd3623a1819683b440b13e2d36288e9436b8
   6 ldap_login auth: move configuration values to auth object init parameters
   7 
   8 diff -r 6e28cd3623a1 -r 9d3f64f9daf4 MoinMoin/auth/ldap_login.py
   9 --- a/MoinMoin/auth/ldap_login.py	Tue Mar 04 20:58:07 2008 +0100
  10 +++ b/MoinMoin/auth/ldap_login.py	Wed Mar 05 12:40:58 2008 +0100
  11 @@ -2,8 +2,8 @@
  12  """
  13      MoinMoin - LDAP / Active Directory authentication
  14  
  15 -    This code only creates a user object, the session has to be established by
  16 -    the auth.moin_session auth plugin.
  17 +    This code only creates a user object, the session will be established by
  18 +    moin automatically.
  19  
  20      python-ldap needs to be at least 2.0.0pre06 (available since mid 2002) for
  21      ldaps support - some older debian installations (woody and older?) require
  22 @@ -11,9 +11,7 @@
  23      "Can't contact LDAP server" - more recent debian installations have tls
  24      support in libldap2 (see dependency on gnutls) and also in python-ldap.
  25  
  26 -    TODO: migrate configuration items to constructor parameters,
  27 -          allow more configuration (alias name, ...) by using
  28 -          callables as parameters
  29 +    TODO: allow more configuration (alias name, ...) by using callables as parameters
  30  
  31      @copyright: 2006-2008 MoinMoin:ThomasWaldmann,
  32                  2006 Nick Phillips
  33 @@ -31,20 +29,90 @@ class LDAPAuth(BaseAuth):
  34  class LDAPAuth(BaseAuth):
  35      """ get authentication data from form, authenticate against LDAP (or Active
  36          Directory), fetch some user infos from LDAP and create a user object
  37 -        for that user. The session is kept by the moin_session auth plugin.
  38 +        for that user. The session is kept by moin automatically.
  39      """
  40  
  41      login_inputs = ['username', 'password']
  42      logout_possible = True
  43      name = 'ldap'
  44 +
  45 +    def __init__(self,
  46 +        server_uri='ldap://localhost',  # ldap / active directory server URI
  47 +                                        # use ldaps://server:636 url for ldaps,
  48 +                                        # use  ldap://server for ldap without tls (and set start_tls to 0),
  49 +                                        # use  ldap://server for ldap with tls (and set start_tls to 1 or 2).
  50 +        bind_dn='',  # We can either use some fixed user and password for binding to LDAP.
  51 +                     # Be careful if you need a % char in those strings - as they are used as
  52 +                     # a format string, you have to write %% to get a single % in the end.
  53 +                     #bind_dn = 'binduser@example.org' # (AD)
  54 +                     #bind_dn = 'cn=admin,dc=example,dc=org' # (OpenLDAP)
  55 +                     #bind_pw = 'secret'
  56 +                     # or we can use the username and password we got from the user:
  57 +                     #bind_dn = '%(username)s@example.org' # DN we use for first bind (AD)
  58 +                     #bind_pw = '%(password)s' # password we use for first bind
  59 +                     # or we can bind anonymously (if that is supported by your directory).
  60 +                     # In any case, bind_dn and bind_pw must be defined.
  61 +        bind_pw='',
  62 +        base_dn='',  # base DN we use for searching
  63 +                     #base_dn = 'ou=SOMEUNIT,dc=example,dc=org'
  64 +        scope=ldap.SCOPE_SUBTREE, # scope of the search we do (2 == ldap.SCOPE_SUBTREE)
  65 +        referrals=0, # LDAP REFERRALS (0 needed for AD)
  66 +        search_filter='(uid=%(username)s)',  # ldap filter used for searching:
  67 +                                             #search_filter = '(sAMAccountName=%(username)s)' # (AD)
  68 +                                             #search_filter = '(uid=%(username)s)' # (OpenLDAP)
  69 +                                             # you can also do more complex filtering like:
  70 +                                             # "(&(cn=%(username)s)(memberOf=CN=WikiUsers,OU=Groups,DC=example,DC=org))"
  71 +        # some attribute names we use to extract information from LDAP:
  72 +        givenname_attribute=None, # ('givenName') ldap attribute we get the first name from
  73 +        surname_attribute=None, # ('sn') ldap attribute we get the family name from
  74 +        aliasname_attribute=None, # ('displayName') ldap attribute we get the aliasname from
  75 +        email_attribute=None, # ('mail') ldap attribute we get the email address from
  76 +        email_callback=None, # called to make up email address
  77 +        coding='utf-8', # coding used for ldap queries and result values
  78 +        timeout=10, # how long we wait for the ldap server [s]
  79 +        verbose=True, # if True, put lots of LDAP debug info into the log
  80 +        start_tls=0, # 0 = No, 1 = Try, 2 = Required
  81 +        tls_cacertdir='',
  82 +        tls_cacertfile='',
  83 +        tls_certfile='',
  84 +        tls_keyfile='',
  85 +        tls_require_cert=0, # 0 == ldap.OPT_X_TLS_NEVER (needed for self-signed certs)
  86 +        bind_once=False, # set to True to only do one bind - useful if configured to bind as the user on the first attempt
  87 +        ):
  88 +        self.server_uri = server_uri
  89 +        self.bind_dn = bind_dn
  90 +        self.bind_pw = bind_pw
  91 +        self.base_dn = base_dn
  92 +        self.scope = scope
  93 +        self.referrals = referrals
  94 +        self.search_filter = search_filter
  95 +
  96 +        self.givenname_attribute = givenname_attribute
  97 +        self.surname_attribute = surname_attribute
  98 +        self.aliasname_attribute = aliasname_attribute
  99 +        self.email_attribute = email_attribute
 100 +        self.email_callback = email_callback
 101 +
 102 +        self.coding = coding
 103 +        self.timeout = timeout
 104 +        self.verbose = verbose
 105 +
 106 +        self.start_tls = start_tls
 107 +        self.tls_cacertdir = tls_cacertdir
 108 +        self.tls_cacertfile = tls_cacertfile
 109 +        self.tls_certfile = tls_certfile
 110 +        self.tls_keyfile = tls_keyfile
 111 +        self.tls_require_cert = tls_require_cert
 112 +
 113 +        self.bind_once = bind_once
 114 +
 115  
 116      def login(self, request, user_obj, **kw):
 117          username = kw.get('username')
 118          password = kw.get('password')
 119          _ = request.getText
 120  
 121 -        cfg = request.cfg
 122 -        verbose = cfg.ldap_verbose
 123 +        verbose = self.verbose
 124  
 125          # we require non-empty password as ldap bind does a anon (not password
 126          # protected) bind if the password is empty and SUCCEEDS!
 127 @@ -55,32 +123,31 @@ class LDAPAuth(BaseAuth):
 128              try:
 129                  u = None
 130                  dn = None
 131 -                coding = cfg.ldap_coding
 132 +                coding = self.coding
 133                  if verbose: logging.info("Setting misc. ldap options...")
 134                  ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) # ldap v2 is outdated
 135 -                ldap.set_option(ldap.OPT_REFERRALS, cfg.ldap_referrals)
 136 -                ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, cfg.ldap_timeout)
 137 -
 138 -                starttls = cfg.ldap_start_tls
 139 +                ldap.set_option(ldap.OPT_REFERRALS, self.referrals)
 140 +                ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout)
 141 +
 142                  if hasattr(ldap, 'TLS_AVAIL') and ldap.TLS_AVAIL:
 143                      for option, value in (
 144 -                        (ldap.OPT_X_TLS_CACERTDIR, cfg.ldap_tls_cacertdir),
 145 -                        (ldap.OPT_X_TLS_CACERTFILE, cfg.ldap_tls_cacertfile),
 146 -                        (ldap.OPT_X_TLS_CERTFILE, cfg.ldap_tls_certfile),
 147 -                        (ldap.OPT_X_TLS_KEYFILE, cfg.ldap_tls_keyfile),
 148 -                        (ldap.OPT_X_TLS_REQUIRE_CERT, cfg.ldap_tls_require_cert),
 149 -                        (ldap.OPT_X_TLS, starttls),
 150 +                        (ldap.OPT_X_TLS_CACERTDIR, self.tls_cacertdir),
 151 +                        (ldap.OPT_X_TLS_CACERTFILE, self.tls_cacertfile),
 152 +                        (ldap.OPT_X_TLS_CERTFILE, self.tls_certfile),
 153 +                        (ldap.OPT_X_TLS_KEYFILE, self.tls_keyfile),
 154 +                        (ldap.OPT_X_TLS_REQUIRE_CERT, self.tls_require_cert),
 155 +                        (ldap.OPT_X_TLS, self.start_tls),
 156                          #(ldap.OPT_X_TLS_ALLOW, 1),
 157                      ):
 158                          if value:
 159                              ldap.set_option(option, value)
 160  
 161 -                server = cfg.ldap_uri
 162 +                server = self.server_uri
 163                  if verbose: logging.info("Trying to initialize %r." % server)
 164                  l = ldap.initialize(server)
 165                  if verbose: logging.info("Connected to LDAP server %r." % server)
 166  
 167 -                if starttls and server.startswith('ldap:'):
 168 +                if self.start_tls and server.startswith('ldap:'):
 169                      if verbose: logging.info("Trying to start TLS to %r." % server)
 170                      try:
 171                          l.start_tls_s()
 172 @@ -90,22 +157,22 @@ class LDAPAuth(BaseAuth):
 173                          raise
 174  
 175                  # you can use %(username)s and %(password)s here to get the stuff entered in the form:
 176 -                ldap_binddn = cfg.ldap_binddn % locals()
 177 -                ldap_bindpw = cfg.ldap_bindpw % locals()
 178 -                l.simple_bind_s(ldap_binddn.encode(coding), ldap_bindpw.encode(coding))
 179 -                if verbose: logging.info("Bound with binddn %r" % ldap_binddn)
 180 +                binddn = self.bind_dn % locals()
 181 +                bindpw = self.bind_pw % locals()
 182 +                l.simple_bind_s(binddn.encode(coding), bindpw.encode(coding))
 183 +                if verbose: logging.info("Bound with binddn %r" % binddn)
 184  
 185                  # you can use %(username)s here to get the stuff entered in the form:
 186 -                filterstr = cfg.ldap_filter % locals()
 187 +                filterstr = self.search_filter % locals()
 188                  if verbose: logging.info("Searching %r" % filterstr)
 189 -                attrs = [getattr(cfg, attr) for attr in [
 190 -                                         'ldap_email_attribute',
 191 -                                         'ldap_aliasname_attribute',
 192 -                                         'ldap_surname_attribute',
 193 -                                         'ldap_givenname_attribute',
 194 -                                         ] if getattr(cfg, attr) is not None]
 195 -                lusers = l.search_st(cfg.ldap_base, cfg.ldap_scope, filterstr.encode(coding),
 196 -                                     attrlist=attrs, timeout=cfg.ldap_timeout)
 197 +                attrs = [getattr(self, attr) for attr in [
 198 +                                         'email_attribute',
 199 +                                         'aliasname_attribute',
 200 +                                         'surname_attribute',
 201 +                                         'givenname_attribute',
 202 +                                         ] if getattr(self, attr) is not None]
 203 +                lusers = l.search_st(self.base_dn, self.scope, filterstr.encode(coding),
 204 +                                     attrlist=attrs, timeout=self.timeout)
 205                  # we remove entries with dn == None to get the real result list:
 206                  lusers = [(dn, ldap_dict) for dn, ldap_dict in lusers if dn is not None]
 207                  if verbose:
 208 @@ -123,27 +190,27 @@ class LDAPAuth(BaseAuth):
 209                      return CancelLogin(_("Invalid username or password."))
 210  
 211                  dn, ldap_dict = lusers[0]
 212 -                if not cfg.ldap_bindonce:
 213 +                if not self.bind_once:
 214                      if verbose: logging.info("DN found is %r, trying to bind with pw" % dn)
 215                      l.simple_bind_s(dn, password.encode(coding))
 216                      if verbose: logging.info("Bound with dn %r (username: %r)" % (dn, username))
 217  
 218 -                if cfg.ldap_email_callback is None:
 219 -                    if cfg.ldap_email_attribute:
 220 -                        email = ldap_dict.get(cfg.ldap_email_attribute, [''])[0].decode(coding)
 221 +                if self.email_callback is None:
 222 +                    if self.email_attribute:
 223 +                        email = ldap_dict.get(self.email_attribute, [''])[0].decode(coding)
 224                      else:
 225                          email = None
 226                  else:
 227 -                    email = cfg.ldap_email_callback(ldap_dict)
 228 +                    email = self.email_callback(ldap_dict)
 229  
 230                  aliasname = ''
 231                  try:
 232 -                    aliasname = ldap_dict[cfg.ldap_aliasname_attribute][0]
 233 +                    aliasname = ldap_dict[self.aliasname_attribute][0]
 234                  except (KeyError, IndexError):
 235                      pass
 236                  if not aliasname:
 237 -                    sn = ldap_dict.get(cfg.ldap_surname_attribute, [''])[0]
 238 -                    gn = ldap_dict.get(cfg.ldap_givenname_attribute, [''])[0]
 239 +                    sn = ldap_dict.get(self.surname_attribute, [''])[0]
 240 +                    gn = ldap_dict.get(self.givenname_attribute, [''])[0]
 241                      if sn and gn:
 242                          aliasname = "%s, %s" % (sn, gn)
 243                      elif sn:
 244 diff -r 6e28cd3623a1 -r 9d3f64f9daf4 MoinMoin/config/multiconfig.py
 245 --- a/MoinMoin/config/multiconfig.py	Tue Mar 04 20:58:07 2008 +0100
 246 +++ b/MoinMoin/config/multiconfig.py	Wed Mar 05 12:40:58 2008 +0100
 247 @@ -338,64 +338,6 @@ Lists: * bullets; 1., a. numbered items.
 248      language_default = 'en'
 249      language_ignore_browser = False # ignore browser settings, use language_default
 250                                      # or user prefs
 251 -
 252 -    # ldap / active directory server URI
 253 -    # use ldaps://server:636 url for ldaps,
 254 -    # use  ldap://server for ldap without tls (and set ldap_start_tls to 0),
 255 -    # use  ldap://server for ldap with tls (and set ldap_start_tls to 1 or 2).
 256 -    ldap_uri = 'ldap://localhost'
 257 -
 258 -    # We can either use some fixed user and password for binding to LDAP.
 259 -    # Be careful if you need a % char in those strings - as they are used as
 260 -    # a format string, you have to write %% to get a single % in the end.
 261 -    #ldap_binddn = 'binduser@example.org' # (AD)
 262 -    #ldap_binddn = 'cn=admin,dc=example,dc=org' # (OpenLDAP)
 263 -    #ldap_bindpw = 'secret'
 264 -    # or we can use the username and password we got from the user:
 265 -    #ldap_binddn = '%(username)s@example.org' # DN we use for first bind (AD)
 266 -    #ldap_bindpw = '%(password)s' # password we use for first bind
 267 -    # or we can bind anonymously (if that is supported by your directory).
 268 -    # In any case, ldap_binddn and ldap_bindpw must be defined.
 269 -    ldap_binddn = ''
 270 -    ldap_bindpw = ''
 271 -
 272 -    # base DN we use for searching
 273 -    #ldap_base = 'ou=SOMEUNIT,dc=example,dc=org'
 274 -    ldap_base = ''
 275 -
 276 -    # scope of the search we do (2 == ldap.SCOPE_SUBTREE)
 277 -    ldap_scope = 2 # we do not want to import ldap for everybody just for that
 278 -
 279 -    # LDAP REFERRALS
 280 -    ldap_referrals = 0 # (0 needed for AD)
 281 -
 282 -    # ldap filter used for searching:
 283 -    #ldap_filter = '(sAMAccountName=%(username)s)' # (AD)
 284 -    ldap_filter = '(uid=%(username)s)' # (OpenLDAP)
 285 -    # you can also do more complex filtering like:
 286 -    # "(&(cn=%(username)s)(memberOf=CN=WikiUsers,OU=Groups,DC=example,DC=org))"
 287 -
 288 -    # some attribute names we use to extract information from LDAP:
 289 -    ldap_givenname_attribute = None # ('givenName') ldap attribute we get the first name from
 290 -    ldap_surname_attribute = None # ('sn') ldap attribute we get the family name from
 291 -    ldap_aliasname_attribute = None # ('displayName') ldap attribute we get the aliasname from
 292 -    ldap_email_attribute = None # ('mail') ldap attribute we get the email address from
 293 -    ldap_email_callback = None # called to make up email address
 294 -
 295 -    ldap_coding = 'utf-8' # coding used for ldap queries and result values
 296 -    ldap_timeout = 10 # how long we wait for the ldap server [s]
 297 -    ldap_verbose = True # if True, put lots of LDAP debug info into the log
 298 -
 299 -    # TLS / SSL related defaults
 300 -    ldap_start_tls = 0 # 0 = No, 1 = Try, 2 = Required
 301 -    ldap_tls_cacertdir = ''
 302 -    ldap_tls_cacertfile = ''
 303 -    ldap_tls_certfile = ''
 304 -    ldap_tls_keyfile = ''
 305 -    ldap_tls_require_cert = 0 # 0 == ldap.OPT_X_TLS_NEVER (needed for self-signed certs)
 306 -
 307 -    ldap_bindonce = False # set to True to only do one bind.  Useful if
 308 -                          # configured to bind as the user on the first attempt
 309  
 310      log_reverse_dns_lookups = True  # if we do reverse dns lookups for logging hostnames
 311                                      # instead of just IPs

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] (2008-03-05 11:52:27, 16.0 KB) [[attachment:ldap_login_refactored.patch]]
 All files | Selected Files: delete move to page copy to page

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