From 4c9aedc873ab8fb15f07467492ff6de1821e805b Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Wed, 19 Jun 2013 10:27:48 -0700 Subject: [PATCH] Add basic https push support When enabled (Config.pm $httpspushurl set), certificates will be automatically created at install time. Currently only https pushing for the mob user is supported. --- .gitmodules | 3 ++ Girocco/Config.pm | 56 +++++++++++++++++++++-- apache.conf | 92 ++++++++++++++++++++++++++++++++++++++ cgi/html.cgi | 18 +++++--- ezcert.git | 1 + gitweb/indextext.html | 5 ++- hooks/update | 5 ++- html/mob.html | 65 +++++++++++++++++++++++++++ html/rootcert.html | 77 ++++++++++++++++++++++++++++++++ install.sh | 120 +++++++++++++++++++++++++++++++++++++++++++++++++- jailsetup.sh | 9 ++-- 11 files changed, 431 insertions(+), 20 deletions(-) create mode 160000 ezcert.git create mode 100644 html/rootcert.html diff --git a/.gitmodules b/.gitmodules index 30746e9..27422e7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "bzr-fastimport.git"] path = bzr-fastimport.git url = git://repo.or.cz/bzr-fastimport/rorcz.git +[submodule "ezcert.git"] + path = ezcert.git + url = git://repo.or.cz/ezcert.git diff --git a/Girocco/Config.pm b/Girocco/Config.pm index 3edff10..cd2a103 100644 --- a/Girocco/Config.pm +++ b/Girocco/Config.pm @@ -71,6 +71,12 @@ our $min_gc_interval = 604800; # 1 week # This will get COMPLETELY OVERWRITTEN by each make install!!! our $basedir = '/home/repo/repomgr'; +# Path where the automatically generated non-user certificates will be stored +# (The per-user certificates are always stored in $chroot/etc/sshcerts/) +# This is preserved by each make install and MUST NOT be under $basedir! +# Not used unless $httpspushurl is defined +our $certsdir = '/home/repo/certs'; + # The repository collection # "$reporoot-recyclebin" will also be created for use by toolbox/trash-project.pl our $reporoot = "/srv/git"; @@ -94,6 +100,38 @@ our $cgiroot = "/home/repo/WWW"; our $webreporoot = "/home/repo/WWW/r"; +## Certificates (only used if $httpspushurl is defined) + +# path to root certificate (undef to use automatic root cert) +# this certificate is made available for easy download and should be whatever +# the root certificate is for the https certificate being used by the web server +our $rootcert = undef; + +# The certificate to sign user push client authentication certificates with (undef for auto) +# The automatically generated certificate should always be fine +our $clientcert = undef; + +# The private key for $clientcert (undef for auto) +# The automatically generated key should always be fine +our $clientkey = undef; + +# The client certificate chain suffix (a pemseq file to append to user client certs) (undef for auto) +# The automatically generated chain should always be fine +# This suffix will also be appended to the $mobusercert before making it available for download +our $clientcertsuffix = undef; + +# The mob user certificate signed by $clientcert (undef for auto) +# The automatically generated certificate should always be fine +# Not used unless $mob is set to 'mob' +# The $clientcertsuffix will be appended before making $mobusercert available for download +our $mobusercert = undef; + +# The private key for $mobusercert (undef for auto) +# The automatically generated key should always be fine +# Not used unless $mob is set to 'mob' +our $mobuserkey = undef; + + ## URL addresses # URL of the gitweb.cgi script (must be in pathinfo mode) @@ -112,6 +150,8 @@ our $htmlurl = "http://repo.or.cz/h"; our $httppullurl = "http://repo.or.cz/r"; # HTTPS push URL of the repository collection (undef if N/A) +# If this is defined, the openssl command must be available +# Normally this should be set to $httppullurl with http: replaced with https: our $httpspushurl = undef; # Git URL of the repository collection (undef if N/A) @@ -119,7 +159,7 @@ our $httpspushurl = undef; # do this particular thing for you.) our $gitpullurl = "git://repo.or.cz"; -# Pushy URL of the repository collection (undef if N/A) +# Pushy SSH URL of the repository collection (undef if N/A) our $pushurl = "ssh://repo.or.cz/$jailreporoot"; # URL of gitweb of this Girocco instance (set to undef if you're not nice @@ -239,13 +279,23 @@ $jailreporoot =~ s,^/+,,; ($reporoot) or die "Girocco::Config \$reporoot must be set"; ($jailreporoot) or die "Girocco::Config \$jailreporoot must be set"; (not $mob or $mob eq 'mob') or die "Girocco::Config \$mob must be undef (or '') or 'mob'"; +$rootcert = "$certsdir/girocco_root_crt.pem" if $httpspushurl && !$rootcert; +$clientcert = "$certsdir/girocco_client_crt.pem" if $httpspushurl && !$clientcert; +$clientkey = "$certsdir/girocco_client_key.pem" if $httpspushurl && !$clientkey; +$clientcertsuffix = "$certsdir/girocco_client_suffix.pem" if $httpspushurl && !$clientcertsuffix; +$mobusercert = "$certsdir/girocco_mob_user_crt.pem" if $httpspushurl && $mob && !$mobusercert; +$mobuserkey = "$certsdir/girocco_mob_user_key.pem" if $httpspushurl && $mob && !$mobuserkey; +our $mobpushurl = $pushurl; +$mobpushurl =~ s,^ssh://,ssh://mob@,i if $mobpushurl; +our $httpsdnsname = ($httpspushurl =~ m,https://([A-Za-z0-9.-]+),i) ? lc($1) : undef if $httpspushurl; ($mirror or $push) or die "Girocco::Config: neither \$mirror nor \$push is set?!"; -(not $push or ($pushurl or $gitpullurl or $httppullurl)) or die "Girocco::Config: no pull URL is set"; -(not $push or $pushurl) or die "Girocco::Config: \$push set but \$pushurl is undef"; +(not $push or ($pushurl or $httpspushurl or $gitpullurl or $httppullurl)) or die "Girocco::Config: no pull URL is set"; +(not $push or ($pushurl or $httpspushurl)) or die "Girocco::Config: \$push set but \$pushurl and \$httpspushurl are undef"; (not $mirror or $mirror_user) or die "Girocco::Config: \$mirror set but \$mirror_user is undef"; ($manage_users == $chrooted) or die "Girocco::Config: \$manage_users and \$chrooted must be set to the same value"; (not $chrooted or $permission_control ne 'ACL') or die "Girocco::Config: resolving uids for ACL not supported when using chroot"; (grep { $permission_control eq $_ } qw(Group Hooks)) or die "Girocco::Config: \$permission_control must be set to Group or Hooks"; ($chrooted or not $mob) or die "Girocco::Config: mob user supported only in the chrooted mode"; +(not $httpspushurl or $httpsdnsname) or die "Girocco::Config invalid \$httpspushurl does not start with https://domainname"; 1; diff --git a/apache.conf b/apache.conf index 3463696..60bdb1c 100644 --- a/apache.conf +++ b/apache.conf @@ -32,6 +32,8 @@ Allow from all Satisfy all + + # Change this to use a git-http-backend not in /usr/lib/git-core/ Options None AllowOverride None @@ -46,8 +48,98 @@ SetEnv GIT_PROJECT_ROOT /srv/git SetEnv GIT_HTTP_EXPORT_ALL 1 + # By default non-smart HTTP fetch access will be allowed, however + # by defining SmartHTTPOnly (or changing the sense of the IfDefine tests) + # non-smart HTTP requests can be denied directly by the web server + + + # These accelerate non-smart HTTP access to loose objects and packs AliasMatch ^/r/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$ /srv/git/$1 AliasMatch ^/r/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$ /srv/git/$1 + + + + # Disable non-smart HTTP access + RewriteEngine On + RewriteCond %{REQUEST_METHOD} !^POST$ + RewriteRule ^/r/.*(? + + # Change this to use a git-http-backend not in /usr/lib/git-core/ ScriptAlias /r/ /usr/lib/git-core/git-http-backend/ + + +# This comments out the following so this file can be used as-is + + + +# This is example configuration of an https virtualhost running Girocco, as set +# up at repo.or.cz; unfortunately, completely independent from Girocco::Config. +# It is not essential for Girocco to use a special virtualhost, however. +# The Config.pm $httpspushurl variable needs to be defined to properly enable +# https pushing. + + + # These certificate files will all be automatically generated, but the + # paths here may need to be corrected to match the paths + # (especially $certsdir) from Config.pm + + SSLCertificateFile /home/repo/certs/girocco_www_crt.pem + SSLCertificateKeyFile /home/repo/certs/girocco_www_key.pem + SSLCertificateChainFile /home/repo/certs/girocco_www_chain.pem + # when using a paid www server cert, only the above three lines should + # be changed. Changing any of the below two lines (other than updating + # the paths to match $certsdir) will likely break https client auth + SSLCACertificateFile /home/repo/certs/girocco_root_crt.pem + SSLCADNRequestFile /home/repo/certs/girocco_client_crt.pem + + SSLVerifyDepth 3 + SSLOptions +FakeBasicAuth +StrictRequire + SSLEngine on + + SSLRequireSSL + + + # This configuration allows fetching over https without a certificate + # while always requiring a certificate for pushing over https + RewriteEngine On + SSLVerifyClient optional + RewriteCond %{QUERY_STRING} (^|&)service=git-receive-pack(&|$) + RewriteRule ^/r/.*/info/refs$ - [env=client_auth_required:1] + RewriteRule ^/r/.*/git-receive-pack$ - [env=client_auth_required:1] + RewriteCond %{ENV:client_auth_required} 1 + RewriteCond %{SSL:SSL_CLIENT_VERIFY} !^SUCCESS$ + RewriteRule .* %{REQUEST_URI} [R=401] + + Order deny,allow + Deny from env=client_auth_required + SSLOptions +FakeBasicAuth + AuthName "Git Client Authentication" + AuthType Basic + AuthBasicProvider anon + Anonymous * + Require valid-user + Satisfy any + + + # *** IMPORTANT *** + # + # ALL the entire contents from the section at + # the top of this file must be copied here. + # + # To avoid this duplication, the contents of the + # section above can be moved to a separate file and then included + # both here and in the section using an Include + # directive. Be careful not to place the new include file in one of the + # directories the standard apache configuration blindly includes all + # files from. + + + + +# End commenting + diff --git a/cgi/html.cgi b/cgi/html.cgi index a206bda..2c108f1 100755 --- a/cgi/html.cgi +++ b/cgi/html.cgi @@ -13,9 +13,11 @@ use Girocco::Config; # Ultra-trivial templating engine; # /^@section=SECTION # /^@heading=HEADING -# /^@header produces HTML header based on @section and @heading -# /@@gitweburl@@/ substitute for gitweburl configuration variable - +# /^@header produces HTML header based on @section and @heading +# /@@gitweburl@@/ substitute for gitweburl configuration variable +# /@@ifmob@@...@@end@@/ remove unless mob defined +# /@@ifssh@@...@@end@@/ remove unless pushurl defined +# /@@ifhttps@@...@@end@@/ remove unless httpspushurl defined my $pathinfo = $ENV{PATH_INFO}; $pathinfo =~ s,^/,,; @@ -39,7 +41,13 @@ if ($pathinfo =~ /\.png$/) { my ($gcgi, $section, $heading); -while (