Changeset - a444c46a0649
[Not reviewed]
default
0 1 0
Mads Kiilerich - 7 years ago 2019-01-07 01:58:16
mads@kiilerich.com
Grafted from: 6e3f4c3e3dbe
middleware: fix handling of Git 'info/refs' command to give correct access control

For a pull, the Git client first sends an 'info/refs' command with a
'service=git-upload-pack' query, then it sends the actual 'git-upload-pack'
command.

For a push, the Git client first sends an 'info/refs' command with a
'service=git-receive-pack' query, then it sends the actual 'git-receive-pack'
command.

Before, the 'info/refs' commands would fall back to the default of trying to
use the action of the previous request. That seems wrong.

Instead, authorize the 'info/refs' command just like the actual command it
references.

path_info will now be checked more than before. Mainly because that is more
correct and more explicit and "better" to do it that way. It might also give
some safety.
1 file changed with 18 insertions and 15 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/middleware/simplegit.py
Show inline comments
 
@@ -145,28 +145,31 @@ class SimpleGit(BaseVCSController):
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def __get_action(self, environ):
 
        """
 
        Maps Git request commands into a pull or push command.
 

	
 
        :param environ:
 
        Maps Git request commands into 'pull' or 'push'.
 
        """
 
        service = environ['QUERY_STRING'].split('=')
 

	
 
        if len(service) > 1:
 
            service_cmd = service[1]
 
            mapping = {
 
                'git-receive-pack': 'push',
 
                'git-upload-pack': 'pull',
 
            }
 
            op = mapping[service_cmd]
 
            self._git_stored_op = op
 
            # try to fallback to stored variable as we don't know if the last
 
            # operation is pull/push
 
        mapping = {
 
            'git-receive-pack': 'push',
 
            'git-upload-pack': 'pull',
 
        }
 
        path_info = environ.get('PATH_INFO', '')
 
        m = GIT_PROTO_PAT.match(path_info)
 
        if m is not None:
 
            cmd = m.group(2)
 
            if cmd == 'info/refs':
 
                service = environ['QUERY_STRING'].split('=')
 
                cmd = service[1] if len(service) > 1 else None
 
                if cmd in mapping:
 
                    self._git_stored_op = mapping[cmd]
 
            elif cmd in mapping:
 
                self._git_stored_op = mapping[cmd]
 
        # fallback to stored variable as we don't know if the last
 
        # operation is pull/push
 
        return self._git_stored_op
 

	
 
    def _handle_githooks(self, repo_name, action, baseui, environ):
 
        """
 
        Handles pull action, push is handled by post-receive hook
 
        """
0 comments (0 inline, 0 general)