8304
Comment: Added an underscore to the second character class of $r_file
|
5641
Correct link to repo
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
As described on MultipleCommitters, one way of collaboration (the CVS-like model) is setting up a central repository every user pushes his changes to and pulls the others' changes from. This page describes how to create such repositories accessible via a shared ssh account without needing to give full shell access to other people. |
= Shared SSH = {{{#!wiki tip This page describes how to create repositories accessible via a '''single shared SSH account''' without needing to give full shell access to other people. This is just one of many ways to make your repository available to [[MultipleCommitters|multiple committers]], and not necessarily the most common. See PublishingRepositories for a good overview of many ways to allow others to interact with your repository. }}} == hg-ssh == hg-ssh is a python script available in [[https://www.mercurial-scm.org/repo/hg-stable/raw-file/tip/contrib/hg-ssh|contrib/hg-ssh]] and was probably installed along with your Mercurial software. Allowed repositories are managed directly in the `authorized_keys` file. |
Line 7: | Line 8: |
== How this works == | Look at the [[https://www.mercurial-scm.org/repo/hg-stable/file/tip/contrib/hg-ssh#l12|start of the script]] for usage instructions. When possible use the version that matches your installed version of Mercurial. |
Line 9: | Line 10: |
When accessing a remote repository via mercurial's ssh repository type, ''hg'' basically does a |
A step-by-step guide for adding a `hg` user and configuring hg-ssh can be found [[https://sites.google.com/site/ucdcsssg/announcements/howtocollaborateusingmercurialwithhg-ssh|here]]. See [[SecuringRepositories]] for guidance on how to '''secure''' a Mercurial repository published via SSH. == mercurial-server == {{{#!wiki note Despite its name, this is not a Mercurial server. It offers an improved management interface for the shared ssh mechanism like that provided by hg-ssh. }}} mercurial-server provides the most complete and easiest-to-use solution to this problem for hosting a collection of repositories on Unix systems. Installing mercurial-server creates a new user, `hg`, which will own all the repositories to be shared. Giving access to a new user is as simple as adding their SSH key to a special repository and pushing the changes. mercurial-server can enforce fine-grained permissions and logs all events. * http://www.lshift.net/mercurial-server.html mercurial-server is descended from hg-ssh. Root privileges are required to install it. == hg-login == HgLogin is a system by MarcSchaefer for creating restricted shared user accounts. == hg-gateway == "hg-gateway" is inspired by "hg-ssh" and is useful in shared hosting like situations where you wanted to give multiple users hg access via SSH on the same SSH/unix user account. "hg-gateway" is useful in situations such as shared web hosting accounts where you do not have root access nor the ability to create additional users. Each hg user can be given access some subset of the hg repositories on the server and can even be restricted to have read-only access. "hg-gateway" has a command line interface for common administration tasks such as adding new users, granting users permission to repositories etc. Installing "hg-gateway" is easy (edit one script variable and add a line to your authorized_keys) and does not require root access. Details at http://parametricity.net/b/hg-gateway == hgadmin == hgadmin also contains a wrapper for ssh (like "hg-ssh"). Unlike hg-ssh, this wrapper will examine the web-permissions in the managed repository to determine whether access is allowed. hgadmin also includes a script to automatically generate the web-permissions, to manage http passwords (contained in a htpasswd file) and to manage ssh keys. Its configuration supports users and groups, and has a syntax mostly like the standard svn access configuration. hgadmin can be found at https://bitbucket.org/JakobKrainz/hgadmin == hgssh2 == A python script to control ssh access to mercurial repositories, modified from hg-ssh. It allows you to specify a simple config file to control the access permissions: {{{ [USER_NAME] repo2 = read repo3 = write }}} https://github.com/dengzhp/hgssh2 == hgssh3 == A python script to control ssh access to mercurial repositories, modified from hg-ssh and hgssh2. It allows you to specify a simple config file to define friendly/short names for repositories and access controls per user: {{{ [reponame] user1 = read user2 = write }}} [[https://bitbucket.org/painfulcranium/hgssh3/|https://bitbucket.org/painfulcranium/hgssh3]] == How these work == When accessing a remote repository via Mercurial's `ssh` repository type, `hg` basically does the following: |
Line 15: | Line 76: |
It relies on `ssh` for authentication and tunneling. When using public key authentication, `ssh` allows limiting the user to one specific command (as described in the [[http://www.openbsd.org/cgi-bin/man.cgi?query=sshd&sektion=8|sshd manual page]] in the section concerning the `authorized_keys` file format). Such a command, provided by the solutions listed above, can do the necessary sanity checking around the requested operation, and can then call `hg` just like `ssh` would do in the example above. Since every user gets his own private key and his own entry in `authorized_keys`, the solutions presented here are able to distinguish between different users and thus enforce things like access control, even though a single system account (or system user) may be providing the underlying services. Moreover, since a designated command must be executed when those accessing the repository authenticate themselves, it should not be possible for users to start a normal shell and bypass access controls implemented by the designated command (although this does depend on the implementation and proper functioning of the command itself). | |
Line 16: | Line 78: |
and relies on ssh for authentication and tunneling. When using public key authentication, ssh allows limiting the user to one specific command, which can do all the sanity checks we want and then calls ''hg'' just like ssh would in the example above. Note that every user gets his own private key and his own entry in authorized_keys, which allows the scripts to distinguish between different users and thus enforce e.g. access permissions. |
See also AclExtension, HgWebDirStepByStep, PublishingRepositories, and MultipleCommitters |
Line 23: | Line 80: |
There are two alternative implementations of scripts which provide access only to explicitly allowed repositories: = hg-ssh = A python script available in [http://www.selenic.com/hg/?f=-1;file=contrib/hg-ssh;style=raw contrib/hg-ssh]. Allowed repositories are managed directly in the authorized_keys file. Look at the start of the script for usage instructions. = hg-login = '''Note:''' The following instructions describe the very personal setup we use on our system. I decided to add this page because the configuration described here a) works for mercurial out of the box and b) solves some problems from [(Link broken) http://www.kitenet.net/~joey/sshcvs/]: In particular, it allows distinguishing multiple committers and a (crude) form of permissions. It is most probably neither the best nor the most elegant way and I don't promise anything more than that it works for me. --- MarcSchaefer == Setting up the shared SSH account for hg-login == The first step is creating a dedicated user on the server side -- let's call it ''mercurial''. Nobody should be able to log into this account with a password, so set the password field in the /etc/passwd (or /etc/shadow) to *. It needs a valid shell though, since sshd always calls scripts through the shell. Then, copy the ''hg-login'' script at the end of this page into the home directory and create a directory ''repositories'', which will contain (wait for it) the repositories (duh). Note that everybody with read/write permissions to the ''repository'' directory can read/write to the repositories directly, so you might want to prevent that. == Allowing connections from a user == Every user needs his own public/private key (see the manpage of ''ssh-keygen'' for how to create one). Append the generated public key to ''~mercurial/.ssh/authorized_keys'' on the server side, prefixed with some options to grant access to mercurial only. More precisely, every line has to look like this: {{{ command="/home/mercurial/hg-login [user]",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-[type] [key] }}} Here ''[user]'' is an identifier which will later be used for granting access to a repository, ''[type]'' is dsa or rsa depending on the key type and ''[key]'' is the key itself, followed by an optional comment. On every connect, the user must be able to present the corresponding private key, for example by adding it to his ssh-agent. == Creating repositories and setting permissions == Creating a shared repository is simple: Just initialise it in ''repositories'' like every other repository. However, nobody will be able to access it unless you grant them permission. To allow a user to access the repository ''~mercurial/repositories/<repos>'', create a file ''~mercurial/repositories/<repos>.allow'' which contains his username (the one from ''authorized_keys'') alone on a line. Note that it is not possible to only grant read rights -- it's full access or nothing. == The hg-login script == The following is a (Perl) script (sorry ;) ) to mediate the access to the shared repositories. It first of all checks the supplied username and the command that is to be executed for sanity (usernames must be alphanumeric, starting with a letter), then normalises and checks the repository path (creating subdirectories in ''repositories'' is allowed, but file names must match ^[a-zA-Z0-9][a-zA-Z0-9-:+.]$). Only if these checks pass and the desired repository exists and allows access by the user, the server process is started. {{{ #!/usr/bin/perl -w -T use strict; $ENV{PATH} = '/usr/local/bin:/usr/bin:/bin'; my $hg = '/usr/local/bin/hg'; my $repositories = '/home/mercurial/repositories'; # The following character classes describe the allowed user- # and repository names. Note that we forbid all path constituents # which begin with a dot -- look ma, no directory traversal. my $r_user = qr#[a-zA-Z][a-zA-Z0-9]*#; my $r_file = qr#[a-zA-Z0-9][a-zA-Z0-9-:+._]*#; # The username is given as the first argument (from command= # in authorized_keys), sshd is kind enough to pass the requested # command as an environment variable. my $user_in = $ARGV[0]; my $cmd_in = $ENV{SSH_ORIGINAL_COMMAND} || ''; # First, basic sanity checking on the username. The assignment # is necessary to convince Perl that the username is no longer # tainted. defined $user_in or die "No username given.\n"; my ($user) = $user_in =~ /^($r_user)$/ or die "Invalid username `$user_in'.\n"; # The command passed by hg has a very specific structure: Check that. my ($repos) = $cmd_in =~ m#^hg -R (\S+) serve --stdio$# or die "Invalid command `$cmd_in' requested.\n"; # Now for the repository path: We assume that it consists of $r_files # separated by slashes. Leading and trailing ones are ignored. s#^/+##, s#/+$##, s#/+#/#g for $repos; my $path = ''; foreach my $file_in (split m#/#, $repos) { my ($file) = $file_in =~ /^($r_file)$/ or die "Invalid repository path `$repos'"; $path .= "/$file"; } # Only the toplevel-directory of every mercurial repository contains # a subdir `.hg'. -d "$repositories/$path/.hg" or die "No such repository `$path'.\n"; # Now for permissions ... open my $perms, '<', "$repositories/$path.allow" or die "No such repositoriy `$path'.\n"; chomp( my @allowed_in = <$perms> ); close $perms; my $allowed = ''; $user eq $_ and $allowed = 1 for @allowed_in; $allowed or die "No such repository `$path'.\n"; # Ok, everything is in order: go for it. exec $hg, '-R', "$repositories/$path", 'serve', '--stdio'; die "Unable to exec `hg' on repository `$path' ($!)\n"; }}} == Extending above to allow read only access for some == Using a hook and slightly extending above, you can implement read only access for some users. Change {{{ $user eq $_ and $allowed = 1 for @allowed_in; }}} to {{{ my $allowed = ''; for (@allowed_in) { if ($user eq $_) { $allowed = 1; $ENV{READ_WRITE} = 1; last; } elsif ("${user}.ro" eq $_) { $allowed = 1; $ENV{READ_ONLY} = 1; last; } } }}} Then add a hook via {{{.hgrc}}} like so... {{{ [hooks] pretxnchangegroup.deny.lock = /path/to/lock_script }}} Where {{{lock_script}}} is a simple shell script like {{{ #!/bin/ksh if [[ "x${READ_ONLY}" != "x" ]]; then print "You do not have write access." 1>&2 exit 1 fi exit 0 }}} Now any users in the {{{allow}}} file above specified like {{{ someuser.ro }}} will have read only access while others will have read write access. == Further enhancement to allow even finer grained control == The above can be further extended to add {{{ # allow more control via hooks $ENV{SSH_HG_USER} = $user; }}} just before {{{ exec $hg, '-R', "$repositories/$path", 'serve', '--stdio'; }}} By doing so, the hooks can make use of the {{{SSH_HG_USER}}} env. variable and make even more fine grained access control decisions e.g. {{{ #!/bin/ksh if [[ "x${SSH_HG_USER}" == "xmpm" ]]; then print "Allowing access to mpm" 1>&2 else print "You are not mpm. Access denied." 1>&2 exit 1 fi exit 0 }}} |
---- CategoryWeb CategoryHowTo |
Shared SSH
This page describes how to create repositories accessible via a single shared SSH account without needing to give full shell access to other people. This is just one of many ways to make your repository available to multiple committers, and not necessarily the most common. See PublishingRepositories for a good overview of many ways to allow others to interact with your repository.
hg-ssh
hg-ssh is a python script available in contrib/hg-ssh and was probably installed along with your Mercurial software. Allowed repositories are managed directly in the authorized_keys file.
Look at the start of the script for usage instructions. When possible use the version that matches your installed version of Mercurial.
A step-by-step guide for adding a hg user and configuring hg-ssh can be found here. See SecuringRepositories for guidance on how to secure a Mercurial repository published via SSH.
mercurial-server
Despite its name, this is not a Mercurial server. It offers an improved management interface for the shared ssh mechanism like that provided by hg-ssh.
mercurial-server provides the most complete and easiest-to-use solution to this problem for hosting a collection of repositories on Unix systems. Installing mercurial-server creates a new user, hg, which will own all the repositories to be shared. Giving access to a new user is as simple as adding their SSH key to a special repository and pushing the changes. mercurial-server can enforce fine-grained permissions and logs all events.
mercurial-server is descended from hg-ssh.
Root privileges are required to install it.
hg-login
HgLogin is a system by MarcSchaefer for creating restricted shared user accounts.
hg-gateway
"hg-gateway" is inspired by "hg-ssh" and is useful in shared hosting like situations where you wanted to give multiple users hg access via SSH on the same SSH/unix user account.
"hg-gateway" is useful in situations such as shared web hosting accounts where you do not have root access nor the ability to create additional users. Each hg user can be given access some subset of the hg repositories on the server and can even be restricted to have read-only access. "hg-gateway" has a command line interface for common administration tasks such as adding new users, granting users permission to repositories etc. Installing "hg-gateway" is easy (edit one script variable and add a line to your authorized_keys) and does not require root access.
Details at http://parametricity.net/b/hg-gateway
hgadmin
hgadmin also contains a wrapper for ssh (like "hg-ssh").
Unlike hg-ssh, this wrapper will examine the web-permissions in the managed repository to determine whether access is allowed.
hgadmin also includes a script to automatically generate the web-permissions, to manage http passwords (contained in a htpasswd file) and to manage ssh keys.
Its configuration supports users and groups, and has a syntax mostly like the standard svn access configuration.
hgadmin can be found at https://bitbucket.org/JakobKrainz/hgadmin
hgssh2
A python script to control ssh access to mercurial repositories, modified from hg-ssh.
It allows you to specify a simple config file to control the access permissions:
[USER_NAME] repo2 = read repo3 = write
https://github.com/dengzhp/hgssh2
hgssh3
A python script to control ssh access to mercurial repositories, modified from hg-ssh and hgssh2.
It allows you to specify a simple config file to define friendly/short names for repositories and access controls per user:
[reponame] user1 = read user2 = write
https://bitbucket.org/painfulcranium/hgssh3
How these work
When accessing a remote repository via Mercurial's ssh repository type, hg basically does the following:
$ ssh hg.example.com hg -R /path/to/repos serve --stdio
It relies on ssh for authentication and tunneling. When using public key authentication, ssh allows limiting the user to one specific command (as described in the sshd manual page in the section concerning the authorized_keys file format). Such a command, provided by the solutions listed above, can do the necessary sanity checking around the requested operation, and can then call hg just like ssh would do in the example above. Since every user gets his own private key and his own entry in authorized_keys, the solutions presented here are able to distinguish between different users and thus enforce things like access control, even though a single system account (or system user) may be providing the underlying services. Moreover, since a designated command must be executed when those accessing the repository authenticate themselves, it should not be possible for users to start a normal shell and bypass access controls implemented by the designated command (although this does depend on the implementation and proper functioning of the command itself).
See also AclExtension, HgWebDirStepByStep, PublishingRepositories, and MultipleCommitters