changeset 605:72bed56219d6

security bugfix simplehg wasn't checking for permissions on remote commands different than pull or push.
author Marcin Kuzminski <marcin@python-works.com>
date Mon, 18 Oct 2010 03:06:38 +0200
parents 5cc96df705b9
children f31f1327c1e9
files rhodecode/lib/middleware/simplehg.py
diffstat 1 files changed, 51 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/lib/middleware/simplehg.py	Mon Oct 18 03:04:58 2010 +0200
+++ b/rhodecode/lib/middleware/simplehg.py	Mon Oct 18 03:06:38 2010 +0200
@@ -39,7 +39,7 @@
 import logging
 import os
 import traceback
- 
+
 log = logging.getLogger(__name__)
 
 class SimpleHg(object):
@@ -49,7 +49,7 @@
         self.config = config
         #authenticate this mercurial request using 
         self.authenticate = AuthBasicAuthenticator('', authfunc)
-        
+
     def __call__(self, environ, start_response):
         if not is_mercurial(environ):
             return self.application(environ, start_response)
@@ -66,7 +66,7 @@
                 REMOTE_USER.update(environ, result)
             else:
                 return result.wsgi_application(environ, start_response)
-        
+
         try:
             repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
             if repo_name.endswith('/'):
@@ -74,7 +74,7 @@
         except:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
-        
+
         #===================================================================
         # CHECK PERMISSIONS FOR THIS REQUEST
         #===================================================================
@@ -87,24 +87,26 @@
                 log.error(traceback.format_exc())
                 return HTTPInternalServerError()(environ, start_response)
             #check permissions for this repository
-            if action == 'pull':
+
+            if action == 'push':
+                if not HasPermissionAnyMiddleware('repository.write',
+                                                  'repository.admin')\
+                                                    (user, repo_name):
+                    return HTTPForbidden()(environ, start_response)
+
+            else:
                 if not HasPermissionAnyMiddleware('repository.read',
                                                   'repository.write',
                                                   'repository.admin')\
                                                     (user, repo_name):
                     return HTTPForbidden()(environ, start_response)
-            if action == 'push':
-                if not HasPermissionAnyMiddleware('repository.write',
-                                                  'repository.admin')\
-                                                    (user, repo_name):
-                    return HTTPForbidden()(environ, start_response)
-            
+
             #log action    
             proxy_key = 'HTTP_X_REAL_IP'
             def_key = 'REMOTE_ADDR'
             ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
-            self.__log_user_action(user, action, repo_name, ipaddr)            
-        
+            self.__log_user_action(user, action, repo_name, ipaddr)
+
         #===================================================================
         # MERCURIAL REQUEST HANDLING
         #===================================================================
@@ -124,16 +126,16 @@
         except Exception:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
-        
+
         #invalidate cache on push
         if action == 'push':
             self.__invalidate_cache(repo_name)
             messages = []
             messages.append('thank you for using rhodecode')
-        
+
             return self.msg_wrapper(app, environ, start_response, messages)
         else:
-            return app(environ, start_response)           
+            return app(environ, start_response)
 
 
     def msg_wrapper(self, app, environ, start_response, messages=[]):
@@ -141,9 +143,9 @@
         Wrapper for custom messages that come out of mercurial respond messages
         is a list of messages that the user will see at the end of response 
         from merurial protocol actions that involves remote answers
-        @param app:
-        @param environ:
-        @param start_response:
+        :param app:
+        :param environ:
+        :param start_response:
         """
         def custom_messages(msg_list):
             for msg in msg_list:
@@ -154,17 +156,18 @@
     def __make_app(self):
         hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
         return  self.__load_web_settings(hgserve)
-    
+
     def __get_environ_user(self, environ):
         return environ.get('REMOTE_USER')
-    
+
     def __get_user(self, username):
         return get_user_cached(username)
-        
+
     def __get_action(self, environ):
         """
         Maps mercurial request commands into a pull or push command.
-        @param environ:
+        This should return generally always something
+        :param environ:
         """
         mapping = {'changegroup': 'pull',
                    'changegroupsubset': 'pull',
@@ -172,50 +175,51 @@
                    'listkeys': 'pull',
                    'unbundle': 'push',
                    'pushkey': 'push', }
-        
         for qry in environ['QUERY_STRING'].split('&'):
             if qry.startswith('cmd'):
                 cmd = qry.split('=')[-1]
                 if mapping.has_key(cmd):
                     return mapping[cmd]
-    
+                else:
+                    return cmd
+
     def __log_user_action(self, user, action, repo, ipaddr):
         action_logger(user, action, repo, ipaddr)
-        
+
     def __invalidate_cache(self, repo_name):
         """we know that some change was made to repositories and we should
         invalidate the cache to see the changes right away but only for
         push requests"""
         invalidate_cache('cached_repo_list')
         invalidate_cache('full_changelog', repo_name)
-           
-                   
+
+
     def __load_web_settings(self, hgserve):
-        #set the global ui for hgserve
+        #set the global ui for hgserve instance passed
         hgserve.repo.ui = self.baseui
-        
+
         hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
         repoui = make_ui('file', hgrc, False)
-        
-        
+
+
         if repoui:
             #overwrite our ui instance with the section from hgrc file
             for section in ui_sections:
                 for k, v in repoui.configitems(section):
                     hgserve.repo.ui.setconfig(section, k, v)
-            
+
         return hgserve
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
+
+
+
+
+
+
+
+
+
+
+
+
+
+