июля
02
2011
2

[nginx] configure gitosis and basic http auth for git-http-backend

2. Path gitosis:

git am --signoff < feauture_http_auth.patch

From 815cf347c83465fb9fe20977198e12b9d438b014 Mon Sep 17 00:00:00 2001
From: Arkady Smirnov <smirnov.arkady@gmail.com>
Date: Sat, 2 Jul 2011 20:35:28 +0300
Subject: [PATCH] Add http-auth feature
 
---
 gitosis/httpauth.py |  119 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gitosis/run_hook.py |    5 ++
 2 files changed, 124 insertions(+), 0 deletions(-)
 create mode 100644 gitosis/httpauth.py
 
diff --git a/gitosis/httpauth.py b/gitosis/httpauth.py
new file mode 100644
index 0000000..eda96ff
--- /dev/null
+++ b/gitosis/httpauth.py
@@ -0,0 +1,119 @@
+import os, errno, re
+import logging
+
+log = logging.getLogger('gitosis.httpautch')
+
+from gitosis import util
+from gitosis import access
+
+_ACCEPTABLE_USER_RE = re.compile(r'^[a-zA-Z][a-zA-Z0-9_.-]*(@[a-zA-Z][a-zA-Z0-9.-]*)?$')
+
+def isSafeUsername(user):
+    match = _ACCEPTABLE_USER_RE.match(user)
+    return (match is not None)
+
+def _extract_reldir(topdir, dirpath):
+    if topdir == dirpath:
+        return '.'
+    prefix = topdir + '/'
+    assert dirpath.startswith(prefix)
+    reldir = dirpath[len(prefix):]
+    return reldir
+
+def WriteHtpasswd(config, keydir):
+    repositories = util.getRepositoryDir(config)
+    
+    def _error(e):
+        if e.errno == errno.ENOENT:
+            pass
+        else:
+            raise e
+    for (dirpath, dirnames, filenames) \
+        in os.walk(repositories, onerror=_error):
+        
+        reldir = _extract_reldir(
+            topdir=repositories,
+            dirpath=dirpath,
+            )
+        
+        log.debug('Walking %r, seeing %r', reldir, dirnames)
+        to_recurse = []
+        repos = []
+        for dirname in dirnames:
+            if dirname.endswith('.git'):
+                repos.append(dirname)
+            else:
+                to_recurse.append(dirname)
+        dirnames[:] = to_recurse
+        
+        for repo in repos:
+            reponame, ext = os.path.splitext(repo)
+            if reldir != '.':
+                reponame = os.path.join(reldir, reponame)
+            assert ext == '.git'
+            
+            log.debug('http-auth for repo %r', repo)
+            
+            htpasswd_w = os.path.join(dirpath, repo, '.htpasswd-write')
+            htpasswd_r = os.path.join(dirpath, repo, '.htpasswd-read')
+            tmpw = '%s.%d.tmp' % (htpasswd_w, os.getpid())
+            tmpr = '%s.%d.tmp' % (htpasswd_r, os.getpid())
+            
+            try:
+                outw = file(tmpw, 'w')
+                outr = file(tmpr, 'w')
+            
+            
+                for filename in os.listdir(keydir):
+                    if filename.startswith('.'):
+                        continue
+                    
+                    username, ext = os.path.splitext(filename)
+                    if ext != '.htpasswd':
+                        continue
+                    
+                    if not isSafeUsername(username):
+                        log.warn('Unsafe HTTP-AUTH username in keyfile: %r', filename)
+                        continue
+                    
+                    path = os.path.join(keydir, filename)
+                    f = file(path)
+                    log.debug('OPEN %r', path)
+                    
+                    # write access is always sufficient
+                    newpath = access.haveAccess(
+                        config=config,
+                        user=username,
+                        mode='writable',
+                        path=reponame)
+                    
+                    if newpath is None:
+                        newpath = access.haveAccess(
+                            config=config,
+                            user=username,
+                            mode='readonly',
+                            path=reponame)
+                        
+                        if newpath is not None:
+                            log.debug('USERNAME = %r has readonly access', username)
+                            for line in f:
+                                line = line.rstrip('\n')
+                                print >>outr, line
+                    else:
+                        log.debug('USERNAME = %r has write access', username)
+                        for line in f:
+                            line = line.rstrip('\n')
+                            print >>outw, line
+                            print >>outr, line
+                    
+                    f.close()
+                    os.fsync(outw)
+                    os.fsync(outr)
+                    
+            finally:
+                outw.close()
+                outr.close()
+            
+            os.rename(tmpw, htpasswd_w)
+            os.rename(tmpr, htpasswd_r)
+
diff --git a/gitosis/run_hook.py b/gitosis/run_hook.py
index e535e6a..f8d089b 100644
--- a/gitosis/run_hook.py
+++ b/gitosis/run_hook.py
@@ -10,6 +10,7 @@ import shutil
 
 from gitosis import repository
 from gitosis import ssh
+from gitosis import httpauth
 from gitosis import gitweb
 from gitosis import gitdaemon
 from gitosis import app
@@ -47,6 +48,10 @@ def post_update(cfg, git_dir):
         path=authorized_keys,
         keydir=os.path.join(export, 'keydir'),
         )
+    httpauth.WriteHtpasswd(
+        config=cfg,
+        keydir=os.path.join(export, 'keydir'),
+        )
 
 class Main(app.App):
     def create_parser(self):
-- 
1.7.0.4

3. Nginx config

server {
        listen       80;
        server_name  git.example.com;
 
        open_file_cache          max=1000  inactive=20s;
        open_file_cache_valid    30s;
        open_file_cache_min_uses 2;
        open_file_cache_errors   on;
 
        client_max_body_size 500m;
        proxy_buffering off;
 
        # Enable chunk support
        # https://github.com/agentzh/chunkin-nginx-module
        chunkin on;
        error_page 411 = @my_411_error;
        location @my_411_error {
            chunkin_resume;
        }
 
        set $git_root /home/git/repositories;
 
        if ($uri ~ "^(/[^/]+\.git)(.*)" ) {
            set $git_project $git_root$1; 
            set $git_export_ok $git_project/git-daemon-export-ok; 
        }
 
        if ( !-d $git_project ) {
            return 401;
        }
 
        if ($arg_service ~* "git-receive-pack") {
            rewrite ^ /git-auth/write$uri last;
        }      
 
        if ( -f $git_export_ok ) {
            rewrite ^ /git/public$uri last;
        }
 
        # default auth-read action
        rewrite ^ /git-auth/read$uri last;
 
        location ~ ^/git/public(/.*) {
            internal;
            # fcgiwrap is set up to listen on this host:port
            fastcgi_pass        unix:/var/run/git-backend-fcgi;
            fastcgi_param       SCRIPT_FILENAME     /usr/lib/git-core/git-http-backend;
            #fastcgi_param      GIT_HTTP_EXPORT_ALL "";
            fastcgi_param       GIT_PROJECT_ROOT    $git_root;
            fastcgi_param       PATH_INFO           $1;
            fastcgi_param       REMOTE_USER         $remote_user;
            include             fastcgi_params;
        }
 
        location ~ ^/git-auth/read(/.*) {
            internal;
            auth_basic "git-auth";
            auth_basic_user_file $git_project/.htpasswd-read;
 
            # fcgiwrap is set up to listen on this host:port
            fastcgi_pass        unix:/var/run/git-backend-fcgi;
            fastcgi_param       SCRIPT_FILENAME     /usr/lib/git-core/git-http-backend;
            fastcgi_param       GIT_HTTP_EXPORT_ALL "";
            fastcgi_param       GIT_PROJECT_ROOT    $git_root;
            fastcgi_param       PATH_INFO           $1;
            fastcgi_param       REMOTE_USER         $remote_user;
            include             fastcgi_params;
        }
 
        location ~ ^/git-auth/write(/.*) {
            internal;
            auth_basic "git-auth";
            auth_basic_user_file $git_project/.htpasswd-write;
 
            # fcgiwrap is set up to listen on this host:port
            fastcgi_pass        unix:/var/run/git-backend-fcgi;
            fastcgi_param       SCRIPT_FILENAME     /usr/lib/git-core/git-http-backend;
            fastcgi_param       GIT_HTTP_EXPORT_ALL "";
            fastcgi_param       GIT_PROJECT_ROOT    $git_root;
            fastcgi_param       PATH_INFO           $1;
            fastcgi_param       REMOTE_USER         $remote_user;
            include             fastcgi_params;
        }
 
}
Опубликовал adik в Технотрония | Метки: , ,

Работает на WordPress | Локализация: goodwin.wpbot.ru