changeset 265:2cbc7dc436d7

auth changes: added u.auth_method, u.auth_attribs and some debug code. Support for switching off some form fields. imported from: moin--main--1.5--patch-268
author Thomas Waldmann <tw@waldmann-edv.de>
date Fri, 02 Dec 2005 00:39:02 +0000
parents 67e1f1d49a97
children 1fb19804a4b9
files MoinMoin/auth.py MoinMoin/logfile/editlog.py MoinMoin/multiconfig.py MoinMoin/request.py MoinMoin/user.py MoinMoin/userform.py
diffstat 6 files changed, 111 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/auth.py	Thu Dec 01 23:32:09 2005 +0000
+++ b/MoinMoin/auth.py	Fri Dec 02 00:39:02 2005 +0000
@@ -2,6 +2,16 @@
 """
     MoinMoin - modular authentication code
 
+    Here are some methods moin can use in cfg.auth authentication method list.
+    The methods from that list get called in that sequence until one returns
+    a user object (not None).
+    
+    The methods give a kw arg "auth_attribs" to User.__init__ that tells
+    which user attribute names are DETERMINED and set by this auth method and
+    must not get changed by the user using the UserPreferences form.
+    It also gives a kw arg "auth_method" that tells the name of the auth
+    method that authentified the user.
+    
     @copyright: (c) Bastian Blank, Florian Festi, Thomas Waldmann
     @license: GNU GPL, see COPYING for details.
 """
@@ -17,7 +27,8 @@
         # ignore invalid cookies, else user can't relogin
         cookie = None
     if cookie and cookie.has_key('MOIN_ID'):
-        u = user.User(request, id=cookie['MOIN_ID'].value)
+        u = user.User(request, id=cookie['MOIN_ID'].value,
+                      auth_method='moin_cookie', auth_attribs=())
         if u.valid:
             return u
     return None
@@ -40,7 +51,10 @@
     if isinstance(request, RequestTwisted):
         username = request.twistd.getUser()
         password = request.twistd.getPassword()
-        u = user.User(request, auth_username=username, password=password)
+        # when using Twisted http auth, we use username and password from
+        # the moin user profile, so both can be changed by user.
+        u = user.User(request, auth_username=username, password=password,
+                      auth_method='http', auth_attribs=())
 
     else:
         env = request.env
@@ -56,7 +70,10 @@
                 # this "normalizes" the login name from {meier, Meier, MEIER} to Meier
                 # put a comment sign in front of next line if you don't want that:
                 username = username.title()
-            u = user.User(request, auth_username=username)
+            # when using http auth, we have external user name and password,
+            # we don't use the moin user profile for those attributes.
+            u = user.User(request, auth_username=username,
+                          auth_method='http', auth_attribs=('name', 'password'))
 
     if u:
         u.create_or_update()
@@ -69,6 +86,7 @@
     """ authenticate via SSL client certificate """
     from MoinMoin.request import RequestTwisted
     u = None
+    changed = False
     # check if we are running Twisted
     if isinstance(request, RequestTwisted):
         return u # not supported if we run twisted
@@ -87,23 +105,38 @@
             commonname_lower = commonname.lower()
             if email_lower or commonname_lower:
                 for uid in user.getUserList():
-                    u = user.User(request, uid)
+                    u = user.User(request, uid,
+                                  auth_method='sslclientcert', auth_attribs=())
                     if email_lower and u.email.lower() == email_lower:
+                        u.auth_attribs = ('email', 'password')
+                        #this is only useful if same name should be used, as
+                        #commonname is likely no CamelCase WikiName
+                        #if commonname_lower != u.name.lower():
+                        #    u.name = commonname
+                        #    changed = True
+                        #u.auth_attribs = ('email', 'name', 'password')
                         break
                     if commonname_lower and u.name.lower() == commonname_lower:
+                        u.auth_attribs = ('name', 'password')
+                        #this is only useful if same email should be used as
+                        #specified in certificate.
+                        #if email_lower != u.email.lower():
+                        #    u.email = email
+                        #    changed = True
+                        #u.auth_attribs = ('name', 'email', 'password')
                         break
                 else:
                     u = None
-                #u = user.User(request, auth_username=username)
 
     if u:
-        u.create_or_update()
+        u.create_or_update(changed)
     if u and u.valid:
         return u
     else:
         return None
 
 def interwiki(request):
+    # TODO use auth_method and auth_attribs for User object
     if request.form.has_key("user"):
         username = request.form["user"][0]
     else:
--- a/MoinMoin/logfile/editlog.py	Thu Dec 01 23:32:09 2005 +0000
+++ b/MoinMoin/logfile/editlog.py	Fri Dec 02 00:39:02 2005 +0000
@@ -50,7 +50,7 @@
         result = 'ip', request.cfg.show_hosts and self.hostname or ''
         if self.userid:
             if not self._usercache.has_key(self.userid):
-                self._usercache[self.userid] = user.User(request, self.userid)
+                self._usercache[self.userid] = user.User(request, self.userid, auth_method="editlog:53")
             userdata = self._usercache[self.userid]
             if userdata.name:
                 pg = wikiutil.getHomePage(request, username=userdata.name)
@@ -72,7 +72,7 @@
         result = 'ip', request.cfg.show_hosts and self.hostname or ''
         if self.userid:
             if not self._usercache.has_key(self.userid):
-                self._usercache[self.userid] = user.User(request, self.userid)
+                self._usercache[self.userid] = user.User(request, self.userid, auth_method="editlog:75")
             userdata = self._usercache[self.userid]
             if userdata.mailto_author and userdata.email:
                 return ('email', userdata.email)
--- a/MoinMoin/multiconfig.py	Thu Dec 01 23:32:09 2005 +0000
+++ b/MoinMoin/multiconfig.py	Fri Dec 02 00:39:02 2005 +0000
@@ -388,7 +388,7 @@
     user_form_remove = []
     
     # attributes we do NOT save to the userpref file
-    user_transient_fields =  ['id', 'valid', 'may', 'auth_username', 'trusted', 'password', 'password2',]
+    user_transient_fields =  ['id', 'valid', 'may', 'auth_username', 'trusted', 'password', 'password2', 'auth_method', 'auth_attribs']
 
     user_homewiki = 'Self' # interwiki name for where user homepages are located
 
--- a/MoinMoin/request.py	Thu Dec 01 23:32:09 2005 +0000
+++ b/MoinMoin/request.py	Fri Dec 02 00:39:02 2005 +0000
@@ -424,9 +424,7 @@
         for auth in self.cfg.auth:
             the_user = auth(self)
             if the_user: return the_user
-
-        # XXX create
-        return user.User(self)
+        return user.User(self, auth_method="request:427")
 
     def reset(self):
         """ Reset request state.
@@ -1041,7 +1039,7 @@
                     for t in self.clock.dump():
                         self.write('<li>%s</li>\n' % t)
                     self.write('</ul>\n')
-
+                self.write('<!-- auth_method == %s -->' % repr(self.user.auth_method))
                 self.write('</body>\n</html>\n\n')
             
         except MoinMoinNoFooter:
@@ -1244,7 +1242,7 @@
 
         # Update saved cookie and set new unregistered user
         self.saved_cookie = ''
-        self.user = user.User(self)
+        self.user = user.User(self, auth_method="request:1245")
 
         # IMPORTANT: Prevent caching of current page and cookie        
         self.disableHttpCaching()
--- a/MoinMoin/user.py	Thu Dec 01 23:32:09 2005 +0000
+++ b/MoinMoin/user.py	Fri Dec 02 00:39:02 2005 +0000
@@ -191,22 +191,33 @@
 class User:
     """A MoinMoin User"""
 
-    def __init__(self, request, id=None, name="", password=None, auth_username=""):
+    def __init__(self, request, id=None, name="", password=None, auth_username="", **kw):
         """ Initialize User object
         
         @param request: the request object
         @param id: (optional) user ID
         @param name: (optional) user name
         @param password: (optional) user password
-        @param auth_username: (optional) already authenticated user
-            name (e.g. apache basic auth)
+        @param auth_username: (optional) already authenticated user name
+                              (e.g. when using http basic auth)
+        @keyword auth_method: method that was used for authentication,
+                              default: 'internal'
+        @keyword auth_attribs: tuple of user object attribute names that are
+                               determined by auth method and should not be
+                               changed by UserPreferences form, default: ().
+                               First tuple element was used for authentication.
         """
         self._cfg = request.cfg
         self.valid = 0
         self.trusted = 0
         self.id = id
         self.auth_username = auth_username
-
+        self.auth_method = kw.get('auth_method', 'internal')
+        self.auth_attribs = kw.get('auth_attribs', ())
+        if self.auth_method == 'internal':
+            import sys, traceback
+            traceback.print_stack(limit=4, file=sys.stderr)
+                                       
         # create some vars automatically
         for tuple in self._cfg.user_form_fields:
             key = tuple[0]
--- a/MoinMoin/userform.py	Thu Dec 01 23:32:09 2005 +0000
+++ b/MoinMoin/userform.py	Fri Dec 02 00:39:02 2005 +0000
@@ -110,7 +110,8 @@
                 return _("Missing password. Please enter user name and password.")
 
             # Load the user data and check for validness
-            theuser = user.User(self.request, name=name, password=password)
+            theuser = user.User(self.request, name=name, password=password,
+                                auth_method='login_userpassword')
             if not theuser.valid:
                 if theuser.disabled:
                     return _('Account "%s" is disabled.') % name
@@ -129,7 +130,8 @@
                  return _("Bad relogin URL.")
 
             # Load the user data and check for validness
-            theuser = user.User(self.request, uid)
+            theuser = user.User(self.request, uid,
+                                auth_method='login_uid')
             if not theuser.valid:
                 return _("Unknown user.")
             
@@ -147,7 +149,7 @@
             if form.has_key('create'):
                 theuser = self.request.get_user()
             else:
-                theuser = user.User(self.request)
+                theuser = user.User(self.request, auth_method="request:152")
                 
             # Require non-empty name
             try:
@@ -187,11 +189,9 @@
                     # Should never happen
                     return "Can't encode password: %s" % str(err)
 
-            # try to get the (optional) email
+            # try to get the (required) email
             email = form.get('email', [''])[0]
             theuser.email = email.strip()
-
-            # Require email if acl is enabled
             if not theuser.email:
                 return _("Please provide your email address. If you lose your"
                          " login information, you can get it by email.")
@@ -220,14 +220,14 @@
                 result = result + util.dumpFormData(form)
             return result
 
-        else: 
+        else: # Save user profile
             if self.request.request_method != 'POST':
                 return _("Use UserPreferences to change your settings or create an account.")
-            # Save user profile
             theuser = self.request.get_user()
                 
-            # Require non-empty name
-            theuser.name = form.get('name', [theuser.name])[0]
+            if not 'name' in theuser.auth_attribs:
+                # Require non-empty name
+                theuser.name = form.get('name', [theuser.name])[0]
             if not theuser.name:
                 return _("Empty user name. Please enter a user name.")
 
@@ -246,28 +246,30 @@
                 else:
                     newuser = 0
 
-            # try to get the password and pw repeat
-            password = form.get('password', [''])[0]
-            password2 = form.get('password2',[''])[0]
+            if not 'password' in theuser.auth_attribs:
+                # try to get the password and pw repeat
+                password = form.get('password', [''])[0]
+                password2 = form.get('password2',[''])[0]
 
-            # Check if password is given and matches with password repeat
-            if password != password2:
-                return _("Passwords don't match!")
-            if not password and newuser:
-                return _("Please specify a password!")
-            # Encode password
-            if password and not password.startswith('{SHA}'):
-                try:
-                    theuser.enc_password = user.encodePassword(password)
-                except UnicodeError, err:
-                    # Should never happen
-                    return "Can't encode password: %s" % str(err)
+                # Check if password is given and matches with password repeat
+                if password != password2:
+                    return _("Passwords don't match!")
+                if not password and newuser:
+                    return _("Please specify a password!")
+                # Encode password
+                if password and not password.startswith('{SHA}'):
+                    try:
+                        theuser.enc_password = user.encodePassword(password)
+                    except UnicodeError, err:
+                        # Should never happen
+                        return "Can't encode password: %s" % str(err)
 
-            # try to get the (optional) email
-            email = form.get('email', [theuser.email])[0]
-            theuser.email = email.strip()
+            if not 'email' in theuser.auth_attribs:
+                # try to get the email
+                email = form.get('email', [theuser.email])[0]
+                theuser.email = email.strip()
 
-            # Require email if acl is enabled
+            # Require email
             if not theuser.email:
                 return _("Please provide your email address. If you lose your"
                          " login information, you can get it by email.")
@@ -278,12 +280,13 @@
                 for uid in users:
                     if uid == theuser.id:
                         continue
-                    thisuser = user.User(self.request, uid)
+                    thisuser = user.User(self.request, uid, auth_method='userform:283')
                     if thisuser.email == theuser.email:
                         return _("This email already belongs to somebody else.")
 
-            # aliasname
-            theuser.aliasname = form.get('aliasname', [theuser.aliasname])[0]
+            if not 'aliasname' in theuser.auth_attribs:
+                # aliasname
+                theuser.aliasname = form.get('aliasname', [theuser.aliasname])[0]
 	    
             # editor size
             theuser.edit_rows = util.web.getIntegerInput(self.request, 'edit_rows', theuser.edit_rows, 10, 60)
@@ -344,10 +347,12 @@
             # subscription for page change notification
             theuser.subscribed_pages = self.decodePageList('subscribed_pages')
                     
-            # save data and send cookie
+            # save data
             theuser.save()            
             self.request.user = theuser
-            self.request.setCookie()
+
+            if 1: # theuser.auth_method == 'moin_cookie': # XXX
+                self.request.setCookie()
 
             result = _("User preferences saved!")
             if _debug:
@@ -490,14 +495,20 @@
         self.make_form()
 
         if self.request.user.valid and not create_only:
-            buttons = [
-                ('save', _('Save')),
-                ('logout', _('Logout')),
-            ]  
+            buttons = [('save', _('Save'))]
+            if self.request.user.auth_method == 'moin_cookie':
+                buttons.append(('logout', _('Logout')))
+            uf_remove = self.cfg.user_form_remove
+            uf_disable = self.cfg.user_form_disable
+            for attr in self.request.user.auth_attribs:
+                if attr == 'password':
+                    uf_remove.append(attr)
+                else:
+                    uf_disable.append(attr)
             for key, label, type, length, textafter in self.cfg.user_form_fields:
                 default = self.cfg.user_form_defaults[key]
-                if not key in self.cfg.user_form_remove:
-                    if key in self.cfg.user_form_disable:
+                if not key in uf_remove:
+                    if key in uf_disable:
                         self.make_row(_(label),
                                   [ html.INPUT(type=type, size=length, name=key, disabled="disabled",
                                     value=getattr(self.request.user, key)), ' ', _(textafter), ])