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

git

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

Best 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)