AuthenticatingHg » History » Version 21

Chris Cannam, 2010-08-13 02:37 PM

1 2 Chris Cannam
h2. Authentication for Mercurial activity
2 2 Chris Cannam
3 2 Chris Cannam
h3. Requirements
4 2 Chris Cannam
5 2 Chris Cannam
# *Clone/pull from repo for public project*: Any user, no authentication required
6 4 Chris Cannam
# *Clone/pull from repo for private project*: Permitted users only
7 4 Chris Cannam
# *Push to repo for public project*: Permitted users only
8 4 Chris Cannam
# *Push to repo for private project*: Permitted users only
9 11 Chris Cannam
# *Create repo for public project*: User with manager role on project
10 12 Chris Cannam
# *Delete repo or carry out command-line admin tasks*: System admin only
11 1 Chris Cannam
12 10 Chris Cannam
What constitutes a permitted user for limited push or pull activity?
13 4 Chris Cannam
14 4 Chris Cannam
* A user who is a member of the project?
15 4 Chris Cannam
* A user who is identified in the [web] section of the repository?
16 4 Chris Cannam
* A user who is both a member and identified in the [web] section?
17 4 Chris Cannam
* A user who is either a member or identified in the [web] section?
18 4 Chris Cannam
* A user who is identified in the [web] section, if any, or is a member if there is no such section?
19 5 Chris Cannam
20 5 Chris Cannam
h3. Techniques
21 1 Chris Cannam
22 18 Chris Cannam
* Hg repository creation using "reposman.rb":/projects/soundsoftware-site/repository/entry/extra/svn/reposman.rb
23 5 Chris Cannam
* Apache authentication against Redmine user database using mod_auth_mysql (no support for LDAP-authenticated users?)
24 18 Chris Cannam
* Apache authentication against Redmine users using "the mod_perl module Redmine.pm":http://redmine.rubyforge.org/svn/trunk/extra/svn/Redmine.pm ("local copy":/projects/soundsoftware-site/repository/entry/extra/svn/Redmine.pm) or a variant thereof.  Redmine.pm was designed for SVN access via WebDAV, but the code itself handles access and authentication only?
25 8 Chris Cannam
* Hg repository [web]-section authorisation using "hgwebdir.cgi":http://mercurial.selenic.com/wiki/PublishingRepositories#Setting_up_the_hgweb.cgi_script
26 7 Chris Cannam
27 7 Chris Cannam
Other links on this subject:
28 7 Chris Cannam
29 8 Chris Cannam
* "Separation between authentication and authorisation activities":http://markmail.org/message/xmav6qg3is3xptve#query:+page:1+mid:xmav6qg3is3xptve+state:results
30 8 Chris Cannam
* "hgrc [web] section":http://www.selenic.com/mercurial/hgrc.5.html#web
31 8 Chris Cannam
* "Using mod_auth_mysql to authenticate against the Redmine database directly":http://maff.ailoo.net/2009/03/authenticate-apache-against-redmine-with-authmysql/
32 14 Chris Cannam
* "Apache2 logging from mod_perl code":http://perl.apache.org/docs/2.0/api/Apache2/Log.html (for use in debugging Redmine.pm)
33 21 Chris Cannam
* "How to automate repository creation":http://www.redmine.org/wiki/1/HowTo_Automate_repository_creation
34 15 Chris Cannam
35 15 Chris Cannam
h3. Plan
36 15 Chris Cannam
37 15 Chris Cannam
We are currently using proxypass from a front-end server to the actual code server, so this complicates matters somewhat.
38 15 Chris Cannam
39 15 Chris Cannam
It seems reasonable-ish to assume that all hg traffic will use SSL.  Apart from anything else, pushes and any other authenticated traffic really must be over SSL, so this avoids irritations when someone pulls from an http URL and then gets kicked out when attempting to push to the default target.
40 15 Chris Cannam
41 15 Chris Cannam
Therefore,
42 15 Chris Cannam
43 15 Chris Cannam
* Front-end server needs to have the relevant certificates
44 15 Chris Cannam
* Front-end server is currently running too old a version of Apache 2 to support SNI, so it can only support one https domain (question: does Mercurial's own Python client support SNI?) -- fortunately for us it is not currently running any other, but this suggests we really need to replace the front-end arch
45 15 Chris Cannam
* Front-end server redirects all http traffic on the hg domain to https and then proxypasses to the back-end server via http (connection is presumed trusted?)
46 15 Chris Cannam
47 15 Chris Cannam
At the back-end server,
48 15 Chris Cannam
49 15 Chris Cannam
* We will use hgwebdir.cgi instead of serving the hg directories directly as static HTTP
50 15 Chris Cannam
* The server's document root will be just a placeholder
51 15 Chris Cannam
* ScriptAlias is used to point all traffic to hgwebdir.cgi
52 18 Chris Cannam
* We will use our own "SoundSoftware.pm":/projects/soundsoftware-site/repository/entry/extra/svn/SoundSoftware.pm based on Redmine.pm to manage access
53 15 Chris Cannam
* We probably want to prevent people reading the list of repositories (so that per-project authentication is always in force)
54 1 Chris Cannam
55 15 Chris Cannam
The net result is that we should have hg over https with basic authentication based on the Redmine database and LDAP as appropriate, with access controls that we can define based on the project rules set out above.
56 1 Chris Cannam
57 19 Chris Cannam
Because of our front-end server limitations, we will use only a single domain name.  That is, hg will be served through https://code.soundsoftware.ac.uk/hg/ rather than https://hg.soundsoftware.ac.uk/ as we might otherwise do.  We can do this straightforwardly, because a ScriptAlias for /hg in the Apache config will take effect before mod_passenger gets to the request (no rewrite needed).
58 19 Chris Cannam
59 19 Chris Cannam
Thus Apache config:
60 15 Chris Cannam
<pre>
61 1 Chris Cannam
PerlLoadModule Apache::Authn::SoundSoftware
62 1 Chris Cannam
63 1 Chris Cannam
<VirtualHost *:80>
64 19 Chris Cannam
        ServerName code.soundsoftware.ac.uk
65 19 Chris Cannam
        ServerAdmin <me>
66 1 Chris Cannam
67 19 Chris Cannam
        DocumentRoot /var/www/redmine/public
68 19 Chris Cannam
        PassengerRestartDir restart_files
69 19 Chris Cannam
        PassengerHighPerformance on
70 19 Chris Cannam
        PassengerMaxRequests 5000
71 19 Chris Cannam
        PassengerStatThrottleRate 10
72 19 Chris Cannam
        RailsSpawnMethod smart
73 19 Chris Cannam
        ExpiresDefault "access plus 1 minute"
74 1 Chris Cannam
75 19 Chris Cannam
        <DirectoryMatch "^/.*/\.svn/">
76 19 Chris Cannam
                Order allow,deny
77 19 Chris Cannam
                Deny from all
78 19 Chris Cannam
                Satisfy All
79 19 Chris Cannam
        </DirectoryMatch>
80 1 Chris Cannam
81 19 Chris Cannam
        <Directory /var/www/redmine/public>
82 19 Chris Cannam
                Options -MultiViews
83 19 Chris Cannam
        </Directory>
84 19 Chris Cannam
85 19 Chris Cannam
        ScriptAlias /hg "/var/hg/index.cgi"
86 19 Chris Cannam
87 19 Chris Cannam
        <Location /hg>
88 19 Chris Cannam
                AuthName "Mercurial"
89 19 Chris Cannam
                AuthType Basic
90 19 Chris Cannam
                Require valid-user
91 19 Chris Cannam
                PerlAccessHandler Apache::Authn::SoundSoftware::access_handler
92 19 Chris Cannam
                PerlAuthenHandler Apache::Authn::SoundSoftware::authen_handler
93 19 Chris Cannam
                SoundSoftwareDSN "DBI:mysql:database=<db>;host=localhost"
94 19 Chris Cannam
                SoundSoftwareDbUser "<user>"
95 19 Chris Cannam
                SoundSoftwareDbPass "<password>"
96 19 Chris Cannam
                SoundSoftwareRepoPrefix "/var/hg/"
97 19 Chris Cannam
                Options +ExecCGI
98 19 Chris Cannam
                AddHandler cgi-script .cgi
99 19 Chris Cannam
                ExpiresDefault now
100 19 Chris Cannam
        </Location>
101 19 Chris Cannam
102 19 Chris Cannam
        ErrorLog /var/log/apache2/error.log
103 19 Chris Cannam
        LogLevel warn
104 19 Chris Cannam
105 19 Chris Cannam
        ServerSignature Off
106 18 Chris Cannam
</VirtualHost>
107 18 Chris Cannam
</pre>
108 18 Chris Cannam
109 20 Chris Cannam
Note that while SoundSoftware.pm is substantially customised from Redmine.pm, /var/hg/index.cgi is a completely stock hgwebdir.cgi (with UTF-8 and, currently, traceback options uncommented).
110 20 Chris Cannam
111 20 Chris Cannam
*Problem:* hgwebdir.cgi refuses to accept authentication if it is not running under SSL (it just spits out "ssl required").  That's reasonable enough, except that the user connection is under SSL, it's just the connection within the virtual host wrapper that is not.  It can be fixed in @hgweb.config@, see below.  We also want to set the config to permit anyone to push, because we are using the mod_perl authentication module rather than the repository configuration to determine who is permitted.
112 18 Chris Cannam
113 15 Chris Cannam
<pre>
114 1 Chris Cannam
[web]
115 1 Chris Cannam
push_ssl = false
116 1 Chris Cannam
allow_push = *
117 1 Chris Cannam
</pre>
118 19 Chris Cannam
119 19 Chris Cannam
*Now...* what about creating repositories?