Trying to make git http backend with mutli repository and multi users

621 views Asked by At

I made a git server with git http backend.
I created 2 repositories (Project1, Project2) and 3 users (user1, user2, user3).

When I clone with command:

 git clone http://myodmain/Project1/  

I want only user1 and user2 to have access to this clone (Project1).

When I clone with command:

git clone http://myodmain/Project2/  

I want only user3 to have access to this clone (Project2), and that user1 and user2 can't access it.

Now, my config server can clone, push, pull, merge,... but all users have the same permission.
Please help me with some examples.

1

There are 1 answers

0
jsvendsgaard On

You have not provided any information on your server setup, so the answer may vary. I think the most important part you are missing is setting up authentication in your web server. However, once you do that, you will run into an issue with git-http-backend, if you wish to authenticate users separately for different repositories. I posted an answer that covers both issues. You may want to view that post as well to view other comments:

Disabling access for git to specific Directory with Apache Basic Authentication

Here is what I originally posted there: Solution Using Apache 2.4

The problem I found is that the git-http-backend script really controls all access to the repositories. Additionally, ScriptAlias is configured as such that it will be routing all /git/ requests to git-http-backend, regardless of the rest of the path. And, because you have provided access to this script for GITGROUP, that group will have access to any repository starting with /git/ in the URL. As per the documentation,

https://git-scm.com/docs/git-http-backend

git-http-backend knows the location to each repository because Apache is providing it with an environment variable. I suspect this means that git-http-backend is the only process on the server that directly accesses your repositories, and then provides the response back to Apache.

My solution adds a few extra steps. Essentially, you would force any access to git-http-backend to occur only after you have already authenticated to the location of your repository, not before. This is done by placing a link to the script in the repository directory itself, and then authenticating that location.

NOTE: I've only done this with bare repositories (git init --bare). I suspect that if for some reason you need to use a non-bare repository, this solution would need some tweaking (Ideas on that at the end):

In a nutshell:

  1. Create a link to git-core in each repository (This is where I suspect you would have an issue if you were to use a non-bare repository, see below for idea on that)
  2. Use ScriptAliasMatch rather than ScriptAlias, so that you can match the request to the requested repository only, and direct the request to the symlink.
  3. Create a <Location> directive for each repository, and set the GIT_PROJECT_ROOT variable individually for each site there. This is because apache is no longer going to be providing the correct path of the repository to git.
  4. Create a <Directory> directive for each symlink. The sole purpose of this for me was to set the options for the directory, like -Indexes. You might use this for other options as needed.

Details:

  1. The link. If your repository is /var/www/html/git/subdir, and your git-httpd-backend is in /usr/libexec/git-core, the command would be:

ln -s /usr/libexec/git-core /var/www/html/git/subdir/git-core

  1. The Alias. This will use a regex with two backreferences, one ($1) to grab the path of the repository, and another ($2) to get the command (git-upload-pack, etc). It then aliases this to the symlink you created in step one. In my regex, I also ensure that the request is a valid git request. It assumes a request to your site would start look like https://yoursite/git/some_repo.git:
ScriptAliasMatch \
  "(?x)^/git/(.*/)((HEAD | \
    info/refs | \
    objects/(info/[^/]+ | \
    [0-9a-f]{2}/[0-9a-f]{38} | \
    pack/pack-[0-9a-f]{40}\.(pack|idx)) | \
    git-(upload|receive)-pack))$" \
    "/var/www/html/git/$1/git-core/git-http-backend/$2"
  1. Create the <Location> directives. This is where you can set the path to the repository for git, and you can also add authentication here:
<Location /git/subdir1.git>
    SetEnv GIT_PROJECT_ROOT /var/www/html/git/subdir1.git
    SetEnv GIT_HTTP_EXPORT_ALL

    AuthType Basic
    AuthName "Authorization Required"
    ... <the rest of your authentication details here> ...
</Location>

<Location /git/subdir2.git>
    SetEnv GIT_PROJECT_ROOT /var/www/html/git/subdir2.git
    SetEnv GIT_HTTP_EXPORT_ALL

    AuthType Basic
    AuthName "Authorization Required"
    ... <the rest of your authentication details here> ...
</Location>
  1. Create the <Directory> directive. For each repository, create a directory for the symlink you created in step A:
<Directory /var/www/html/git/subdir1.git/git-core>
    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch -Indexes
    Allowoverride None
</Directory>

<Directory /var/www/html/git/subdir2.git/git-core>
    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch -Indexes
    Allowoverride None
</Directory>

If you're not using a bare repository:

I only use bare repositories on the git server, but I think that you might see an issue creating this symlink if you didn't have bare repositories. What I'm worried is that someone could somehow add your link to the repository. I'm not sure if this is possible, but a couple of ideas to get around it:

  1. Create a git-ignore for each link, although the repo user might be able to undo this.
  2. Create the symlink in some other directory, outside of the repository directory. The only issue with this I can think of right now, is that you might need to add a second layer of authentication to your directive.