AuthenticatingHg » History » Version 25
Chris Cannam, 2010-09-17 11:37 AM
1 | 25 | Chris Cannam | h1. 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 | 22 | Chris Cannam | h3. Creating repositories |
120 | 22 | Chris Cannam | |
121 | 22 | Chris Cannam | Reposman appears to be set up to create repositories for all projects listed in Redmine, with each repository having the same name as the project. If there is a repository (of any name) already configured for a project, it does not create a new one -- but if the repository that is already configured does have the same name as the project, and it exists on the disk, reposman will test its ownership and permissions and attempt to set them to something it things of as sensible. |
122 | 22 | Chris Cannam | |
123 | 22 | Chris Cannam | I suppose the idea is that Reposman is run regularly (by cron?) in order to update and check the repositories for each project. |
124 | 22 | Chris Cannam | |
125 | 22 | Chris Cannam | *What ownership and permissions are sensible?* We want Redmine (user redmine) to be able to read the repository but it doesn't need to be able to modify it. We need Apache (user www-data) to be able to read and write, so that hgwebdir.cgi can do its work. This suggests we want www-data to own the repository and redmine to be able to read it, so |
126 | 22 | Chris Cannam | |
127 | 22 | Chris Cannam | @drwxr-s--- 17 www-data redmine@ |
128 | 22 | Chris Cannam | |
129 | 22 | Chris Cannam | seems sensible. |
130 | 22 | Chris Cannam | |
131 | 22 | Chris Cannam | Example of running reposman with our instance: @./reposman.rb -s /var/hg -r https://code.soundsoftware.ac.uk/ -k <key> -tv --http-user=user --http-pass=pass -o www-data -g redmine -c "hg init"@ -- note the -tv option says to run in test (and verbose) mode so this doesn't actually change anything. |
132 | 23 | Chris Cannam | |
133 | 23 | Chris Cannam | Reposman doesn't seem to have any option to change the permissions (as opposed to ownerships) of a repository. Actually, we probably don't want it to change the ownerships either -- just to get them right when it first creates a repo. |
134 | 23 | Chris Cannam | |
135 | 23 | Chris Cannam | It would probably be nice for the user who creates or administrates the project to get to choose the repository name. Rather than just creating a repo for every project, even if it's not needed, it might be better if the user could set the repo path in Redmine, and reposman would then check whether the repo existed and create it if it did not. Redmine does happily allow you to set a repository path to something that doesn't exist yet -- though the error message from the repository view tab subsequently is not very helpful (and is SCM-specific). |
136 | 23 | Chris Cannam | |
137 | 24 | Redmine Admin | *A big problem with that* and with the current working of reposman is that the user who creates the project doesn't typically know what repository path to use. For example, a user has just created a project on our test site and typed in "/projects/X/repository" (where X is project name) as the repos path, presumably guessing from the public URL for the browse page. We should either: |
138 | 24 | Redmine Admin | |
139 | 24 | Redmine Admin | # set a sensible repository path for every project on creation (and create the repository automatically) |
140 | 24 | Redmine Admin | # pre-populate the repository path entry field with an appropriate value or prefix |
141 | 24 | Redmine Admin | # provide documentation in the repository settings page |
142 | 24 | Redmine Admin | # check the repository path in reposman and correct it if it is implausible (i.e. if it is a local path that is not in /var/hg or whatever) |
143 | 24 | Redmine Admin | |
144 | 23 | Chris Cannam | *Note*: Reposman has just started failing for me, with "wrong constant name 0" error (see http://www.redmine.org/boards/1/topics/16274) possibly related to introduction of the Checkout plugin. |