📜 ⬆️ ⬇️

Restricting access to repositories

To control access, you can use different solutions gitosys, gitolite, mercurial-server, but these solutions work through SSH, which is not always convenient (there must be a key). In addition, there is not enough flexibility for such solutions.

Primary requirements:


To solve this problem, I made the following system ...
')

Collected nginx with Auth Request module
Part of the configuration file:
 server {
 ...

     location = / auth {
         include / etc / nginx / uwsgi_params;
         uwsgi_pass unix: /tmp/uwsgi.sock;
     }

     location / hg {
         set $ project "";
         if ($ uri ~ "^ / hg / ([a-zA-Z0-9 _ \ -] +). * $") {
             set $ project $ 1;
         }
         if ($ project = "") {
             return 403;
         }
         if (! -d / var / projects / $ repo) {
             return 404;
         }
         auth_request / auth;
         include / etc / nginx / proxy_params;
         proxy_redirect off;
         proxy_pass http://127.0.0.1:8002;
     }
 }

127.0.0.1:8002 - in my case hgserve works at this address

All the magic lies in the uwsgi script. Its task is to verify the data received from nginx. And return the code depending on the result of the test (200,401,403).

#!/usr/bin/python # configure db_host = 'localhost' db_name = 'authdb' db_user = 'test' db_pass = 'test' role_id_read = 1 # member role_id_write = 2 # developer # import re import os import base64 import MySQLdb db_conn = MySQLdb.connect(host = db_host, user = db_user, passwd = db_pass, db = db_name) def get_project_info(project_name): global db_conn cursor = db_conn.cursor() query = 'SELECT id,is_private FROM projects WHERE name=%s' cursor.execute(query, (project_name, )) row = cursor.fetchone() cursor.close() return row def get_role_id(project_id, username, password): global db_conn cursor = db_conn.cursor() query = 'SELECT id FROM users WHERE name=%s AND pass=sha1(%s)' cursor.execute(query, (username, password, )) row = cursor.fetchone() if row == None: return -1 user_id = row[0] query = 'SELECT role_id FROM project_user_perm WHERE project_id=%s AND user_id=%s' cursor.execute(query, (project_id, user_id, )) row = cursor.fetchone() cursor.close() if row == None: return 0 return row[0] def can_user_read(project_id, username, password): role_id = get_role_id(project_id, username, password) if role_id == -1: return -1 if role_id == role_id_read or role_id == role_id_write : return 1 return 0 def can_user_write(project_id, username, password): role_id = get_role_id(project_id, username, password) if role_id == -1: return -1 if role_id == role_id_write : return 1 return 0 def ok200(callback): callback('200 OK', []) return [] def err401(callback): callback('401 Unauthorized', [('WWW-Authenticate', 'Basic realm="Restrict"')]) return [] def err403(callback): callback('403 Forbidden', []) return [] def application(env, resp): req_uri = env.get('REQUEST_URI', '') m = re.match('^/(\w+)/(\w+).*$', req_uri) if m == None: return err403(resp) project_name = m.group(2) project_info = get_project_info(project_name) if project_info == None: return err403(resp) req_method = env.get('REQUEST_METHOD', '') if req_method == 'GET' and project_info[1] == 0: return ok200(resp) req_http_auth = env.get('HTTP_AUTHORIZATION', '') if req_http_auth == '': return err401(resp) m = re.match('^Basic ([a-zA-Z0-9=]+)$', req_http_auth) if m == None: return err403(resp) userpass = base64.b64decode(m.group(1)) m = re.match('^(\w+):(\S+)$', userpass) if m == None: return err403(resp) username = m.group(1) password = m.group(2) result = 0 if req_method == 'GET': result = can_user_read(project_info[0], username, password) else: result = can_user_write(project_info[0], username, password) if result == -1: return err401(resp) elif result == 1: return ok200(resp) else: return err403(resp) 


The script is run using uWSGI :
 uwsgi -s /tmp/uwsgi.sock \
     --wsgi-file /var/projects/vcs_auth/vcs_auth_app.py \
     --uid www-data --gid www-data \
     --pidfile /var/run/vcs_auth_app.pid \
     -d /var/log/uwsgi/vcs_auth_app.log


Database schema:
db schema

Source: https://habr.com/ru/post/136449/


All Articles