Attachment 'RemoteAuth.py'

Download

   1 # LEG25062006
   2 # LEG20080704
   3 #   Martin Schwarzbauer added wikipedia_mysql authentication
   4 #
   5 # Several authentication modules which try to log in the use
   6 # into some remote system like pop, ftp, etc.
   7 #
   8 # typically you would use it somehow like:
   9 '''
  10    from RemoteAuth import <auth>, <map>, cookie
  11    auth = [<auth>, <map> <cookie>]
  12    auth_<*>_verbose=True
  13    auth_<auth>_server=<server where to authenticate>
  14    auth_<auth>_ssl=<True|False>
  15    # Create User Profile on first login
  16    # Note: need to login a second time then
  17    user_autocreate=True
  18 '''
  19 #
  20 # the 'cookie' module is a remake of 'moin_cookie', but it does not
  21 # use the username from the login form, instead it expects it to be
  22 # found in the user_obj
  23 #
  24 # the <map> modules, currently 'gecos', map a name from the login
  25 # form, to something else.  Often the <auth> module needs an account
  26 # name or email address, which is not suitable as a WikiName.  The
  27 # <map> modules can help out with this issue.
  28 # map modules:
  29 #   gecos .. gets the gecos field from the /etc/passwd file (or from
  30 #            nss) extracts the name field and sticks the first two
  31 #            strings there together
  32 #
  33 # the <auth> modules use some commonly used protocol which requires
  34 # authentication.  The take the given username and password from the
  35 # login form and try to authenticate with the respective protocol.
  36 # Then they log out immediately from the service.  If the login was
  37 # successful, the user gets authenticated to the Wiki.  So it suffices
  38 # to have e.g. a POP server with the accounts of the users to get a
  39 # kind of Single Signon for your Wiki.
  40 # auth modules:
  41 #   imap .. logs in to an IMAP server.
  42 #   ftp  .. not tested
  43 #
  44 #
  45 # Security note: it is surely prefereable to have the "remote" service
  46 #   run on the same machine as the Wiki, and better even to run it on
  47 #  "localhost".  This would reduce the chance of credencial leaking.
  48 #
  49 # Note: an interesting module would be the 'uri' auth module, it would
  50 #   take an uri in the following form as username:
  51 #
  52 #   proto://user@host  e.g.:
  53 #
  54 #   imaps://fran=FrancisBacon@mail.hiho.com
  55 #
  56 #   the 'uri' module would then use the 'imap' module, set the server
  57 #   to 'mail.hiho.com', the username to 'fran', and auth_imap_ssl to
  58 #   True.  The Wiki username would be set to "FrancisBacon"
  59 #
  60 #   The uri module thus would allow a user to log in with credencials
  61 #   from wherever they please.
  62 #
  63 #   Again note, that the user is not assured that this credencials
  64 #   could eventually be leaked by flaws in the Wiki or in the
  65 #   operating system where it is run.
  66 # History:
  67 #
  68 #   LEG25062006: initial version
  69 #
  70 # TODO:
  71 #   more modules ...
  72 #
  73 # Bugs:
  74 #
  75 #   When logging in (imap), the wiki says "unknown user", however the
  76 #   user gets authenticated.
  77 
  78 
  79 def gecos(request, **kw):
  80     """ not for authentication, but rather for determining
  81         the user name via a Gecos field entry from the
  82         /etc/passwd file on unix-systems.
  83         must be switched in between auth and cookie
  84     """
  85     u = kw.get('user_obj')
  86 
  87     # If there is no user object we are at the wrong place here
  88     if not u:
  89         return u, True
  90 
  91     import sys, traceback, os
  92     from MoinMoin import user
  93 
  94     verbose = request.cfg.auth_gecos_verbose
  95     
  96     # Extract the Gecos field from the nss passwd database
  97     # TODO: access /etc/passwd directly if nss not available
  98     try:
  99         P = os.popen("getent passwd "+u.auth_username,'r')
 100         passwd = P.readline()
 101         P.close
 102         # TODO: fails if the user does not exist
 103         gecos = passwd.split(':')[4]
 104         cn = gecos.split(',')[0]
 105         names = cn.split(' ')
 106         # TODO: verfiy that names is not empty, etc.
 107         u.name = names[0]+names[1]
 108 
 109     except:
 110         info = sys.exc_info()
 111         request.log("GECOS: caught an exception, traceback follows...")
 112         request.log(''.join(traceback.format_exception(*info)))
 113         u.name = u.auth_username
 114 
 115     if verbose:
 116         request.log("GECOS: mapped auth_name %s to name %s" % (u.auth_username, u.name))
 117         
 118     u.auth_method='gecos'
 119     u.auth_attribs=('name', 'auth_username', 'password')
 120     u.create_or_update(True)
 121     return u, True # cookie has to set the cookie to maintain the session alive
 122     
 123 
 124 def cookie(request, **kw):
 125     """ authenticate via the MOIN_ID cookie
 126     this module must be chained in after another authentication
 127     module, it does not login, otherwise.
 128     In contrast to moin_cookie it does not look up the user locally.
 129     """
 130     
 131     username = kw.get('name')
 132     password = kw.get('password')
 133     login = kw.get('login')
 134     logout = kw.get('logout')
 135     u = kw.get('user_obj')
 136     
 137     from MoinMoin import auth, user
 138     import Cookie
 139     
 140     if login:
 141         if not u:
 142             return None, True
 143 
 144         if u.valid:
 145             auth.setCookie(request, u)
 146             return u, True # we make continuing possible, e.g. for smbmount
 147         
 148     try:
 149         cookie = Cookie.SimpleCookie(request.saved_cookie)
 150     except Cookie.CookieError:
 151         # ignore invalid cookies, else user can't relogin
 152         cookie = None
 153         
 154     if cookie and cookie.has_key('MOIN_ID'):
 155         u = user.User(request, id=cookie['MOIN_ID'].value,
 156                       auth_method='cookie', auth_attribs=())
 157         
 158         if logout:
 159             u.valid = 0 # just make user invalid, but remember him
 160             
 161             if u.valid:
 162                 auth.setCookie(request, u) # refreshes cookie lifetime
 163                 return u, True # use True to get other methods called, too
 164             
 165             else: # logout or invalid user
 166                 auth.deleteCookie(request)
 167                 return u, True # we return a invalidated user object, so that
 168             # following auth methods can get the name of
 169             # the user who logged out
 170     return u, True
 171                 
 172                 
 173 def imap(request, **kw):
 174     """ get authentication data from form, authenticate via imap
 175         user profile must be handled e.g. by cookie
 176     """
 177     username = kw.get('name')
 178     password = kw.get('password')
 179     login = kw.get('login')
 180     user_obj = kw.get('user_obj')
 181 
 182     cfg = request.cfg
 183     verbose = cfg.auth_imap_verbose
 184     
 185     if verbose:
 186         request.log("IMAP: got name=%s login=%r" % (username, login))
 187     
 188     # we just intercept login, other requests have to be
 189     # handled by another auth handler
 190     if not login:
 191         return user_obj, True
 192     
 193     import sys, re, imaplib
 194     import traceback
 195     from MoinMoin import user
 196 
 197     u = None
 198 
 199     try:
 200         if cfg.auth_imap_ssl:
 201             M = imaplib.IMAP4_SSL(cfg.auth_imap_server)
 202         else:
 203             M = imaplib.IMAP4(cfg.auth_imap_server)
 204         try:
 205             M.login(username, password)
 206             u = user.User(request,
 207                           auth_username=username,
 208                           name=username,
 209                           password=password,
 210                           auth_method='imap',
 211                           auth_attribs=('name', 'auth_username', 'password',))
 212         except M.error, err:
 213             request.log("IMAP: Login failed: %s" % err)
 214             
 215     except:
 216         info = sys.exc_info()
 217         request.log("IMAP: caught an exception, traceback follows...")
 218         request.log(''.join(traceback.format_exception(*info)))
 219 
 220 
 221     if u:
 222         u.create_or_update(True)
 223     return u, True
 224 
 225 def  wikipedia_mysql(request, **kw):
 226     """ get authentication data from Wikipedia database
 227     """
 228     username = kw.get('name')
 229     password = kw.get('password')
 230     login = kw.get('login')
 231     user_obj = kw.get('user_obj')
 232 
 233     cfg = request.cfg
 234     mysql_host = cfg.auth_wikipedia_mysql_host
 235     mysql_user = cfg.auth_wikipedia_mysql_user
 236     mysql_passwd = cfg.auth_wikipedia_mysql_passwd
 237     mysql_db = cfg.auth_wikipedia_mysql_db
 238    
 239     # we just intercept login, other requests have to be
 240     # handled by another auth handler
 241     if not login:
 242         return user_obj, True
 243     
 244     import sys, re, MySQLdb
 245     import traceback
 246     from MoinMoin import user
 247 
 248     u = None
 249         
 250     try:
 251         conn = MySQLdb.connect(host = mysql_host, user = mysql_user, passwd = mysql_passwd, db = mysql_db)
 252         cursor = conn.cursor()        
 253         query = """
 254         SELECT (user_password = MD5(CONCAT(user_id,'-',MD5('"""+password+"""')))) 
 255         FROM (
 256             SELECT user_id, user_password 
 257             FROM user
 258             WHERE user_name = '"""+username.capitalize()+"""'
 259             ) AS Temp;"""
 260        
 261         cursor.execute(query)
 262         
 263         result = cursor.fetchall() 
 264 
 265         # check if password and username are valid
 266         if len (result) == 1:
 267             if (result[0])[0]:
 268                 
 269                 # request.log("wikipedia_mysql: Login successful")
 270                 # request.log("wikipedia_mysql Username:" + username)
 271                 u = user.User(request,
 272                               auth_username=username,
 273                               name=username,
 274                               password=password,
 275                               auth_method='wikipedia_mysql',
 276                               auth_attribs=('name', 'auth_username', 'password',))
 277                 u.valid = True
 278 
 279     except:
 280         info = sys.exc_info()
 281         request.log("Wikipedia: caught an exception, traceback follows...")
 282         request.log(''.join(traceback.format_exception(*info)))
 283 
 284     if u:
 285         u.create_or_update(True)
 286 
 287     # clean up
 288     cursor.close()
 289     conn.close()
 290         
 291     return u, True
 292     	
 293 def ftp(request, **kw):
 294     """ get authentication data from form, authenticate via ftp
 295         user profile must be handled e.g. by cookie
 296     """
 297     username = kw.get('name')
 298     password = kw.get('password')
 299     login = kw.get('login')
 300     user_obj = kw.get('user_obj')
 301 
 302     cfg = request.cfg
 303     verbose = cfg.auth_ftp_verbose
 304     
 305     if verbose:
 306         request.log("FTP: got name=%s login=%r" % (username, login))
 307     
 308     # we just intercept login, other requests have to be
 309     # handled by another auth handler
 310     if not login:
 311         return user_obj, True
 312     
 313     import sys, re, ftplib
 314     import traceback
 315     from MoinMoin import user
 316 
 317     u = None
 318 
 319     try:
 320         F = ftplib.FTP(cfg.auth_ftp_server, username, password)
 321         u = user.User(request,
 322                       auth_username=username,
 323                       name=username,
 324                       password=password,
 325                       auth_method='ftp',
 326                       auth_attribs=('name', 'auth_username', 'password',))
 327     except:
 328         info = sys.exc_info()
 329         request.log("FTP: caught an exception, traceback follows...")
 330         request.log(''.join(traceback.format_exception(*info)))
 331 
 332     if u:
 333         u.create_or_update(True)
 334     return u, True

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-07-04 22:10:17, 10.5 KB) [[attachment:RemoteAuth.py]]
 All files | Selected Files: delete move to page copy to page

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