New system. No breaking in, just putting files in /etc/mercurial-server
mercurial-serverA set of tools for managing authorization and access control forssh-based Mercurial repositoriesPaul Crowley, paul@lshift.net, 2008This software may be used and distributed according to the termsof the GNU General Public License, incorporated herein by reference.WHAT IT GIVES YOUThese tools make it easier to provide a centralized repository hostwith read/write access to many repositories for many developers.Access control is managed with a special repository on the servercalled "hgadmin"; pushes to this repository immediately change therules that are in effect.Inside "hgadmin" is a "keys" directory containing the SSH keys of alldevelopers who have access, and a file "hg-ssh-access.conf" whichgives a set of rules defining who can do what to what.All of the repositories controlled by these tools are owned by asingle user (the "hg" user in what follows), but many remote users canact on them. We don't use file permissions to achieve that - instead,developers log in as the "hg" user when they connect to the repositoryhost using ssh, using ssh URLs of the form"ssh://hg@repository-host/repository-name". A restricted shellprevents them from using this access for unauthorized purposes.Developers are authenticated only using SSH keys; no other form ofauthentication is supported.QUICK STARTYou will need - "sudo" installed- "sudo" root privileges- an ssh-key set up with ssh-agentEnsure there is no user called "hg" on the repository host, and run"./install" to create them. You are now the sole user able to changeand create repositories on this repository host. To give access toothers, check out hgadmin - as yourself, and on whichever host is mostconvenient, but using the ssh-key with which you set up therepository: mkdir ~/hg cd ~/hg hg clone ssh://hg@repository-host/hgadmin cd hgadminYou can now add other users by putting their keys in an appropriatesubdirectory of the "keys" directory, and control their access byediting hg-ssh-access.conf. Changes will take effect as soon as youpush them to "ssh://hg@repository-host/hgadmin".Users authorized to do so can now also create new repositories on thishost with "clone": hg clone . ssh://hg@repository-host/my-project-nameHG-SSH-ACCESS.CONFEach line of hg-ssh-access.conf has the following syntax:<rule> <condition> <condition> ...Rule is one ofinit - allow any operation, including the creation of new repositorieswrite - allow reads and writes to this file in this repositoryread - allow the repo to be read but reject matching writesdeny - deny all requestsA condition is a globpattern matched against a relative path, one of:user=<globpattern> - user's keyrepo=<globpattern> - repo (as the user supplies it)file=<globpattern> - file in the repobranch=<globpattern> - name of the branchThe first rule in the file which has all its conditions satisfied isused to determine whether an action is allowed.Paths cannot contain any special characters except "/"; glob patternscannot contain any special characters except "/" and "*". "*" matcheszero or more characters not including "/" while "**" matches zero ormore characters including "/".Blank lines and lines that start with "#" are ignored.FILE CONDITIONSThe rules file is used to make four decisions:- Whether to allow a repository to be created- Whether to allow access to a repository- Whether to allow a changeset on a particular branch at all- Whether to allow a changeset to change a particular fileWhen the first two of these decisions are being made, nothing is knownabout what files might be changed, and so all file conditionsautomatically succeed for the purpose of such decisions. This meansthat doing tricky things with file conditions can havecounterintuitive consequences:- You cannot limit read access to a subset of a repository with a"read" rule and a file condition: any user who has access to arepository can read all of it and its full history. Such a rule canonly have the effect of masking a later "write" rule, as in thisexample: read repo=specialrepo file=dontwritethis write repo=specialrepoallows all users to read specialrepo, and to write to all files*except* that any changeset which writes to "dontwritethis" will berejected.- For similar reasons, don't give "init" rules file conditions.- Don't try to deny write access to a particular file on a particularbranch - a developer can write to the file on another branch and thenmerge it in. Either deny all writes to the branch from that user, orallow them to write to all the files they can write to on any branch.In other words, something like this will have the intended effect write user=docs/* branch=docs file=docs/*But something like this will not have the intended effect; it willeffectively allow these users to write to any file on any branch, bywriting it to "docs" first: write user=docs/* branch=docs write user=docs/* file=docs/* read user=docs/*HOW IT WORKSWhen a developer attempts to connect to a repository via ssh, the SSHdaemon searches for a match for that user's key in~hg/.ssh/authorized_keys. If the developer is authorised to connectto the repository they will have an entry in this file. The entryincludes a "command" prefix which specifies that the restricted shellshould be used; this shell is passed an argument identifying thedeveloper. The shell parses the command the developer is trying toexecute, and consults a rules file to see if that developer is allowedto perform that action on that repository. The bulk of the work ofthe restricted shell is done by the Python program "hg-ssh", but theshell script "hg-ssh-wrapper" sets up some configuration so that youcan change it to suit your local installation.The file ~hg/.ssh/authorized_keys is generated by "refresh-auth",which recurses through a directory of files containing SSH keys andgenerates an entry in authorized_keys for each one, using the name ofthe key file as the identifier for the developer. These keys willlive in the "keys" subdirectory of a repository called "hgadmin". Ahook in this repository re-runs "refresh-auth" on the most recentversion after every push.Finally, a hook in an extension is run for each changeset that isremotely committed, which uses the rules file to determine whether toallow the changeset.LOCKING YOURSELF OUTIf you find yourself "locked out" - that is, that you no longer havethe permissions needed in hgadmin - you can break back in again ifyou're able to become the "hg" user on the repository host. Once youare that user, delete ~hg/.ssh/authorized_keys (to stop any user whomight have access but shouldn't from using the repository while youfix things). Then go into ~hg/repos/hgadmin, do an "hg update", editthings to your satisfaction, and commit the change. Finally, run~hg/admin/mercurial-server/refresh-auth ~hg/.ssh/authorized_keys ./hg-ssh-wrapperto regenerate ~hg/.ssh/authorized_keys. THANKSThanks for reading this far. If you use mercurial-server, please tellme about it.Paul Crowley, 2008