changeset 5343:39bac9410169

auth: make the auth module decide which fields are editable by admin and user
author Mads Kiilerich <madski@unity3d.com>
date Fri, 31 Jul 2015 15:44:07 +0200
parents 40cfdd004bf6
children 0a0595b15c6c
files kallithea/controllers/admin/my_account.py kallithea/controllers/admin/users.py kallithea/lib/auth_modules/__init__.py kallithea/lib/auth_modules/auth_container.py kallithea/lib/auth_modules/auth_crowd.py kallithea/lib/auth_modules/auth_internal.py kallithea/lib/auth_modules/auth_ldap.py kallithea/lib/auth_modules/auth_pam.py kallithea/templates/admin/my_account/my_account_profile.html kallithea/templates/admin/users/user_edit_profile.html
diffstat 10 files changed, 51 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/controllers/admin/my_account.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/controllers/admin/my_account.py	Fri Jul 31 15:44:07 2015 +0200
@@ -37,6 +37,7 @@
 
 from kallithea import EXTERN_TYPE_INTERNAL
 from kallithea.lib import helpers as h
+from kallithea.lib import auth_modules
 from kallithea.lib.auth import LoginRequired, NotAnonymous, AuthUser
 from kallithea.lib.base import BaseController, render
 from kallithea.lib.utils2 import generate_api_key, safe_int
@@ -100,6 +101,8 @@
         self.__load_data()
         c.perm_user = AuthUser(user_id=self.authuser.user_id)
         c.ip_addr = self.ip_addr
+        managed_fields = auth_modules.get_managed_fields(c.user)
+        c.readonly = lambda n: 'readonly' if n in managed_fields else None
 
         defaults = c.user.get_dict()
         update = False
@@ -115,12 +118,8 @@
                 form_result = _form.to_python(post_data)
                 # skip updating those attrs for my account
                 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
-                              'new_password', 'password_confirmation']
-                #TODO: plugin should define if username can be updated
-                if c.user.extern_type != EXTERN_TYPE_INTERNAL:
-                    # forbid updating username for external accounts
-                    # TODO: also skip username (and email etc) if self registration not enabled
-                    skip_attrs.append('username')
+                              'new_password', 'password_confirmation',
+                             ] + managed_fields
 
                 UserModel().update(self.authuser.user_id, form_result,
                                    skip_attrs=skip_attrs)
--- a/kallithea/controllers/admin/users.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/controllers/admin/users.py	Fri Jul 31 15:44:07 2015 +0200
@@ -42,7 +42,6 @@
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import LoginRequired, HasPermissionAllDecorator, \
     AuthUser
-import kallithea.lib.auth_modules.auth_internal
 from kallithea.lib import auth_modules
 from kallithea.lib.base import BaseController, render
 from kallithea.model.api_key import ApiKeyModel
@@ -175,11 +174,8 @@
         form_result = {}
         try:
             form_result = _form.to_python(dict(request.POST))
-            skip_attrs = ['extern_type', 'extern_name']
-            #TODO: plugin should define if username can be updated
-            if c.user.extern_type != kallithea.EXTERN_TYPE_INTERNAL:
-                # forbid updating username for external accounts
-                skip_attrs.append('username')
+            skip_attrs = ['extern_type', 'extern_name',
+                         ] + auth_modules.get_managed_fields(c.user)
 
             user_model.update(id, form_result, skip_attrs=skip_attrs)
             usr = form_result['username']
@@ -249,6 +245,8 @@
         c.active = 'profile'
         c.perm_user = AuthUser(user_id=id)
         c.ip_addr = self.ip_addr
+        managed_fields = auth_modules.get_managed_fields(c.user)
+        c.readonly = lambda n: 'readonly' if n in managed_fields else None
 
         defaults = c.user.get_dict()
         return htmlfill.render(
--- a/kallithea/lib/auth_modules/__init__.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/lib/auth_modules/__init__.py	Fri Jul 31 15:44:07 2015 +0200
@@ -416,3 +416,16 @@
             log.warning("User `%s` failed to authenticate against %s"
                         % (username, plugin.__module__))
     return None
+
+def get_managed_fields(user):
+    """return list of fields that are managed by the user's auth source, usually some of
+    'username', 'firstname', 'lastname', 'email', 'active', 'password'
+    """
+    auth_plugins = Setting.get_auth_plugins()
+    for module in auth_plugins:
+        log.debug('testing %s (%s) with auth plugin %s', user, user.extern_type, module)
+        plugin = loadplugin(module)
+        if plugin.name == user.extern_type:
+            return plugin.get_managed_fields()
+    log.error('no auth plugin %s found for %s', user.extern_type, user)
+    return [] # TODO: Fail badly instead of allowing everything to be edited?
--- a/kallithea/lib/auth_modules/auth_container.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/lib/auth_modules/auth_container.py	Fri Jul 31 15:44:07 2015 +0200
@@ -190,3 +190,6 @@
 
         log.info('user `%s` authenticated correctly' % user_data['username'])
         return user_data
+
+    def get_managed_fields(self):
+        return ['username', 'password']
--- a/kallithea/lib/auth_modules/auth_crowd.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/lib/auth_modules/auth_crowd.py	Fri Jul 31 15:44:07 2015 +0200
@@ -229,7 +229,7 @@
             'email': crowd_user["email"] or email,
             'admin': admin,
             'active': active,
-            'active_from_extern': crowd_user.get('active'),
+            'active_from_extern': crowd_user.get('active'), # ???
             'extern_name': crowd_user["name"],
         }
 
@@ -240,3 +240,6 @@
         log.debug("Final crowd user object: \n%s" % (formatted_json(user_data)))
         log.info('user %s authenticated correctly' % user_data['username'])
         return user_data
+
+    def get_managed_fields(self):
+        return ['username', 'firstname', 'lastname', 'email', 'password']
--- a/kallithea/lib/auth_modules/auth_internal.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/lib/auth_modules/auth_internal.py	Fri Jul 31 15:44:07 2015 +0200
@@ -97,3 +97,7 @@
         else:
             log.warning('user %s tried auth but is disabled' % username)
             return None
+
+    def get_managed_fields(self):
+        # Note: 'username' should only be editable (at least for user) if self registration is enabled
+        return []
--- a/kallithea/lib/auth_modules/auth_ldap.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/lib/auth_modules/auth_ldap.py	Fri Jul 31 15:44:07 2015 +0200
@@ -359,3 +359,6 @@
         except (Exception,):
             log.error(traceback.format_exc())
             return None
+
+    def get_managed_fields(self):
+        return ['username', 'firstname', 'lastname', 'email', 'password']
--- a/kallithea/lib/auth_modules/auth_pam.py	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/lib/auth_modules/auth_pam.py	Fri Jul 31 15:44:07 2015 +0200
@@ -136,3 +136,6 @@
         log.debug("pamuser: \n%s" % formatted_json(user_data))
         log.info('user %s authenticated correctly' % user_data['username'])
         return user_data
+
+    def get_managed_fields(self):
+        return ['username', 'password']
--- a/kallithea/templates/admin/my_account/my_account_profile.html	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/templates/admin/my_account/my_account_profile.html	Fri Jul 31 15:44:07 2015 +0200
@@ -19,10 +19,8 @@
            </div>
          </div>
 
-        <% readonly = None %>
         <div class="fields">
             %if c.user.extern_type != c.EXTERN_TYPE_INTERNAL:
-                <% readonly = "readonly" %>
                 <strong>${_('Your user is in an external Source of Record; some details cannot be managed here')}.</strong>
             %endif
              <div class="field">
@@ -30,7 +28,7 @@
                     <label for="username">${_('Username')}:</label>
                 </div>
                 <div class="input">
-                  ${h.text('username',class_='medium', readonly=readonly)}
+                  ${h.text('username',class_='medium', readonly=c.readonly('username'))}
                 </div>
              </div>
 
@@ -39,7 +37,7 @@
                     <label for="name">${_('First Name')}:</label>
                 </div>
                 <div class="input">
-                    ${h.text('firstname',class_="medium")}
+                    ${h.text('firstname',class_="medium", readonly=c.readonly('firstname'))}
                 </div>
              </div>
 
@@ -48,7 +46,7 @@
                     <label for="lastname">${_('Last Name')}:</label>
                 </div>
                 <div class="input">
-                    ${h.text('lastname',class_="medium")}
+                    ${h.text('lastname',class_="medium", readonly=c.readonly('lastname'))}
                 </div>
              </div>
 
@@ -57,8 +55,7 @@
                     <label for="email">${_('Email')}:</label>
                 </div>
                 <div class="input">
-                    ## we should be able to edit email !
-                    ${h.text('email',class_="medium")}
+                    ${h.text('email',class_="medium", readonly=c.readonly('email'))}
                 </div>
              </div>
 
--- a/kallithea/templates/admin/users/user_edit_profile.html	Fri Jul 31 15:44:07 2015 +0200
+++ b/kallithea/templates/admin/users/user_edit_profile.html	Fri Jul 31 15:44:07 2015 +0200
@@ -17,11 +17,9 @@
                 %endif
            </div>
         </div>
-        <% readonly = None %>
         <div class="fields">
             %if c.user.extern_type != c.EXTERN_TYPE_INTERNAL:
              <div class="field">
-               <% readonly = "readonly" %>
                <strong>${_('This user is in an external Source of Record (%s); some details cannot be managed here.' % c.user.extern_type)}.</strong>
              </div>
             %endif
@@ -31,7 +29,7 @@
                     <label for="username">${_('Username')}:</label>
                 </div>
                 <div class="input">
-                  ${h.text('username',class_='medium', readonly=readonly)}
+                  ${h.text('username',class_='medium', readonly=c.readonly('username'))}
                 </div>
              </div>
 
@@ -40,7 +38,7 @@
                     <label for="email">${_('Email')}:</label>
                 </div>
                 <div class="input">
-                    ${h.text('email',class_='medium')}
+                    ${h.text('email',class_='medium', readonly=c.readonly('email'))}
                 </div>
              </div>
 
@@ -67,7 +65,7 @@
                     <label for="new_password">${_('New password')}:</label>
                 </div>
                 <div class="input">
-                    ${h.password('new_password',class_='medium',readonly=readonly)}
+                    ${h.password('new_password',class_='medium',readonly=c.readonly('password'))}
                 </div>
              </div>
 
@@ -76,7 +74,7 @@
                     <label for="password_confirmation">${_('New password confirmation')}:</label>
                 </div>
                 <div class="input">
-                    ${h.password('password_confirmation',class_="medium",readonly=readonly)}
+                    ${h.password('password_confirmation',class_="medium",readonly=c.readonly('password'))}
                 </div>
              </div>
 
@@ -85,7 +83,7 @@
                     <label for="firstname">${_('First Name')}:</label>
                 </div>
                 <div class="input">
-                    ${h.text('firstname',class_='medium')}
+                    ${h.text('firstname',class_='medium', readonly=c.readonly('firstname'))}
                 </div>
              </div>
 
@@ -94,7 +92,7 @@
                     <label for="lastname">${_('Last Name')}:</label>
                 </div>
                 <div class="input">
-                    ${h.text('lastname',class_='medium')}
+                    ${h.text('lastname',class_='medium', readonly=c.readonly('lastname'))}
                 </div>
              </div>
 
@@ -103,7 +101,7 @@
                     <label for="active">${_('Active')}:</label>
                 </div>
                 <div class="checkboxes">
-                    ${h.checkbox('active',value=True)}
+                    ${h.checkbox('active',value=True, readonly=c.readonly('active'))}
                 </div>
              </div>
 
@@ -112,7 +110,7 @@
                     <label for="admin">${_('Admin')}:</label>
                 </div>
                 <div class="checkboxes">
-                    ${h.checkbox('admin',value=True)}
+                    ${h.checkbox('admin',value=True, readonly=c.readonly('admin'))}
                 </div>
              </div>