0.0
No commit activity in last 3 years
No release in over 3 years
Library to handle git requests over SSH
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 10.0
~> 2.13
~> 0.7

Runtime

~> 1.5
 Project Readme

GitHandler Build Status

Accept and handle git repository requests over SSH

Installation

Install using rubygems:

gem install git_handler

Or using latest source code:

git clone git://github.com/sosedoff/git-handler.git
cd git-handler
bundle install
rake install

Usage

If you already have an operation system configured, make sure you have git user in your system. In order to use git_handler you'll need to generate a customized SSH public key and add it to ~/.ssh/authorized_keys on server. Generation should be something that needs to be implemented in your application or script, there is functionality already built for that:

require 'git_handler/public_key'

# Load your current pub key
content = File.read(File.expand_path('~/.ssh/id_rsa.pub'))

# Create a key
key = GitHandler::PublicKey.new(content)

Now, to convert loaded key into a system key just run:

key.to_system_key('/usr/bin/git_proxy')
# => command="/usr/bin/git_proxy",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNjN3ZUOoosWeuJ7KczE5FAOzwZ+Z51KSQvqTCb7ccBi4u+pPYcGEYr2t0cx/BUcx/ZGE8ih+zxN1qM8KmM0uluuy54itHsKFdAwoibkbG22fQc2DY0RmktXXB/w6LxmFuQrmz0fkcbkE39pm5k6Nw6mqks5HjM7aDXRdwM8fSrq0PjfUNiESIrIAeEMGhtZFaj+WZVMfXaIlgzxZsAUpUULhN4j069v8VgxWyyOUT+gwcQB8lVc0BVYhptlFaJBtwhfWvOAviSuK7Cpjh60NdkZ3R2QYeh6wb6fF+KGCkM4iED4PZ1Ep8fRzrbCHky4VHSOyOvg9qKcgP1h+e+diD 

SSH public key is now ready for usage on server side. Drop it into ~/home/git/.ssh/authorized_keys file if your user is git. The whole purpose of key modifications is that we're restricting SSH to a specific command or script on server, which gives us ability to control permissions and other restrictions.

Control script

In the example above as you can see we specify /usr/bin/git_proxy to be executed once SSH connection is being established. GitHandler provides a simple api to verify and execute git request that comes from client.

Example of /usr/bin/git_proxy file:

#!/usr/bin/env ruby
require 'git_handler'

config = GitHandler::Configuration.new

# Configuration has a bunch of options:
# :user       - Git user, default: git
# :home_path  - Home path, default: /home/git
# :repos_path - Path to repositories, default: /home/git/repositories
# :log_path   - Git requests logger, default: /var/log/git_handler.log

begin
  session = GitHandler::Session.new(config)
  session.execute(ARGV, ENV)
rescue Exception => ex
  STDERR.puts "Error: #{ex.message}"
  exit(1)
end

NOTE: Script must have permissions for execution.

Session instance will check if incoming git request has a valid environment and valid git command. After check is complete it will shell out to git-shell -c COMMAND to perform an original git command. Providing block to session.execute will override default and allow you to control the logic:

session.execute(ARGV, ENV) do |request|

  # Yields GitHandler::Request instance that
  # contains all information about git request, env and repo

  STDERR.puts "-----------------------------"
  STDERR.puts "REMOTE IP: #{request.remote_ip}"
  STDERR.puts "ARGS: #{request.args.inspect}"
  STDERR.puts "ENV: #{request.env.inspect}"
  STDERR.puts "REPO: #{request.repo}"
  STDERR.puts "REPO PATH: #{request.repo_path}"
  STDERR.puts "COMMAND: #{request.command}"
  STDERR.puts "-----------------------------"
end

By default, if request has invalid environment attributes or not a git request, session raises GitHandler::SessionError. If you dont want to handle exceptions, just use session.execute_safe method:

session = GitHandler::Session.new(config)
session.execute_safe(ARGV, ENV)

To test if all that works try this:

ssh -vT git@YOUR_HOST.com

In the debug output you'll something similar:

debug1: Remote: Agent forwarding disabled.
debug1: Remote: Pty allocation disabled.
debug1: Remote: Forced command.
debug1: Remote: Port forwarding disabled.
debug1: Remote: X11 forwarding disabled.
debug1: Remote: Agent forwarding disabled.
debug1: Remote: Pty allocation disabled.
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8

>>> Error: Invalid git request <<<<

debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 2384, received 2880 bytes, in 0.3 seconds
Bytes per second: sent 7308.1, received 8828.6
debug1: Exit status 1

This means that everything works. Script does not provide any shell access and only allows git requests. To test that, create an empty repository:

mkdir /home/git/repositories
cd /home/git/repositories
git init --bare testrepo.git

And clone it (on local machine):

git clone git@YOUR_HOST.com:testrepo.git

Server side configuration

In case you dont have a git user on your server, here is a quick manual on how to get it rolling.

Create a git user:

adduser --home /home/git --disabled-password git

Restrict SSH authentication only via public keys. Open file /etc/ssh/sshd_config and add this snippet to the end:

Match User !root
  PasswordAuthentication no

This will disable password authentications for everyone except root, or other user of your choice. You'll need to restart ssh daemon:

/etc/init.d/ssh restart

Authorized Keys

GitHandler provides a simple api to manage your authorized_keys file content.

Each write operation issues a lock File::LOCK_EX on file.

Example:

require 'git_handler/public_key'
require 'git_handler/authorized_keys'

# Read your local ssh public key content
content = File.read(File.expand_path('~/.ssh/id_rsa.pub'))

# Create a new key
key = GitHandler::PublicKey.new(content)

# Write formatted key to authorized_keys file
GitHandler::AuthorizedKeys.write_key('/path/to/file', key, 'my_command')

You can also write multiple keys:

GitHandler::AuthorizedKeys.write_keys('/path/to/file', [k1, k2, k3], 'my_command')

Testing

To run the test suite execute:

rake test

License

See LICENSE file for details