Using git-shell and restricting developers to commit to their own projects

git

Solution

I use something a bit simpler, all you need is to setup three files, the `authorized_keys` file, the `gitsecurity.rb` file and a permissions file `gitpermissions`. For simplicity they can all go in the git accounts .ssh folder. (Basic unix admin skills required to understand herein)

The `gitpermissions` file looks like this, and should be fairly self explanitory:

repo1.git|jane|rw
repo1.git|james|r
repo2.git|bob|rw

The `autorized_keys` file looks something like this:

command="/Users/git/.ssh/gitsecurity.rb jacob",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa rFaivBw.....5Rws jacob
command="/Users/git/.ssh/gitsecurity.rb bob",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa rFaivBw.....5Rws bob

Finally the `gitsecurity.rb` script, just copy and paste it:

#!/usr/bin/ruby

class GitPermission
    attr_accessor :username;
    attr_accessor :repository;
    attr_accessor :read;
    attr_accessor :write;

def initialize(line)
    bits = line.split('|');
    if(bits.length!=3)
        $stderr.puts "Invalid configuration file"
        Process.exit(4)
    end
    @repository = bits[0]
    @username = bits[1]
    @read = bits[2].include?("r")
    @write = bits[2].include?("w")
end

end

if(!ENV.has_key?("SSH_ORIGINAL_COMMAND"))
    $stderr.puts "SSH not allowed to the git account."
    Process.exit(1);
end
command = ENV["SSH_ORIGINAL_COMMAND"];

if(!ARGV.length == 1)
    $stderr.puts "Authorised keys file misconfigured, username not specified correctly."
    Process.exit(1);
end

if(!ARGV[0].match(/^[A-Za-z0-9]+$/))
    $stderr.puts "Authorised keys file misconfigured, username contains invalid characters: "+ARGV[0];
    Process.exit(1);
end
username = ARGV[0]

if(!command.match(/^git[ -]upload-pack /) && !command.match(/^git[ -]receive-pack /))
    $stderr.puts "Only git commands are allowed."
    Process.exit(2);
end

repository = command[(command.index(' ')+1)..-1]

if(!repository.match(/'.*'/))
    $stderr.puts "Repository parameter incorrect."
    Process.exit(2);
end
repository = repository[1,repository.length-2]

begin
    file = File.new("/Users/git/.ssh/gitpermissions", "r")
    while (line = file.gets)
        p = GitPermission.new(line);
        if(p.repository == repository && p.username == username)
            if((p.write == true || (p.read == true && command.match(/^git[ -]upload-pack/))) )
                exec "/usr/local/git/bin/" + command
                Process.exit(0);
            end
        end
    end
    file.close
rescue => err
    $stderr.puts "Problem with server configuration: #{err}"
    Process.exit(4)
end

$stderr.puts "You do not have permission to complete this operation"
Process.exit(5)

Problem

We are using `git-shell` to ensure that the git account is only used for git operations. This works great. However before we move to using git full time, how do we set it up similar to github whereby depending on your public key you may only commit to your own repositories? As far as I can tell the github people may be rolling their own `git-shell`, the source code appears to be very simple to hack

Original source