##// END OF EJS Templates
Comment to memory leak with Postgres and ssl....
Liwiusz Ociepa -
r1402:2eba0b66d428
parent child
Show More
@@ -1,291 +1,291
1 1 package Apache::Authn::Redmine;
2 2
3 3 =head1 Apache::Authn::Redmine
4 4
5 5 Redmine - a mod_perl module to authenticate webdav subversion users
6 6 against redmine database
7 7
8 8 =head1 SYNOPSIS
9 9
10 10 This module allow anonymous users to browse public project and
11 11 registred users to browse and commit their project. Authentication is
12 12 done against the redmine database or the LDAP configured in redmine.
13 13
14 14 This method is far simpler than the one with pam_* and works with all
15 15 database without an hassle but you need to have apache/mod_perl on the
16 16 svn server.
17 17
18 18 =head1 INSTALLATION
19 19
20 20 For this to automagically work, you need to have a recent reposman.rb
21 21 (after r860) and if you already use reposman, read the last section to
22 22 migrate.
23 23
24 24 Sorry ruby users but you need some perl modules, at least mod_perl2,
25 25 DBI and DBD::mysql (or the DBD driver for you database as it should
26 26 work on allmost all databases).
27 27
28 28 On debian/ubuntu you must do :
29 29
30 30 aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
31 31
32 32 If your Redmine users use LDAP authentication, you will also need
33 33 Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
34 34
35 35 aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl
36 36
37 37 =head1 CONFIGURATION
38 38
39 39 ## if the module isn't in your perl path
40 40 PerlRequire /usr/local/apache/Redmine.pm
41 41 ## else
42 42 # PerlModule Apache::Authn::Redmine
43 43 <Location /svn>
44 44 DAV svn
45 45 SVNParentPath "/var/svn"
46 46
47 47 AuthType Basic
48 48 AuthName redmine
49 49 Require valid-user
50 50
51 51 PerlAccessHandler Apache::Authn::Redmine::access_handler
52 52 PerlAuthenHandler Apache::Authn::Redmine::authen_handler
53 53
54 54 ## for mysql
55 55 RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
56 ## for postgres
56 ## for postgres (there is memory leak in libpq+ssl)
57 57 # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server;sslmode=disable"
58 58
59 59 RedmineDbUser "redmine"
60 60 RedmineDbPass "password"
61 # Optional where clause (fulltext search would be slow - and
62 # database dependant).
61 ## Optional where clause (fulltext search would be slow and
62 ## database dependant).
63 63 # RedmineDbWhereClause "and members.role_id IN (1,2)"
64 64 </Location>
65 65
66 66 To be able to browse repository inside redmine, you must add something
67 67 like that :
68 68
69 69 <Location /svn-private>
70 70 DAV svn
71 71 SVNParentPath "/var/svn"
72 72 Order deny,allow
73 73 Deny from all
74 74 # only allow reading orders
75 75 <Limit GET PROPFIND OPTIONS REPORT>
76 76 Allow from redmine.server.ip
77 77 </Limit>
78 78 </Location>
79 79
80 80 and you will have to use this reposman.rb command line to create repository :
81 81
82 82 reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
83 83
84 84 =head1 MIGRATION FROM OLDER RELEASES
85 85
86 86 If you use an older reposman.rb (r860 or before), you need to change
87 87 rights on repositories to allow the apache user to read and write
88 88 S<them :>
89 89
90 90 sudo chown -R www-data /var/svn/*
91 91 sudo chmod -R u+w /var/svn/*
92 92
93 93 And you need to upgrade at least reposman.rb (after r860).
94 94
95 95 =cut
96 96
97 97 use strict;
98 98 use warnings FATAL => 'all';
99 99
100 100 use DBI;
101 101 use Digest::SHA1;
102 102 # optional module for LDAP authentication
103 103 my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
104 104
105 105 use Apache2::Module;
106 106 use Apache2::Access;
107 107 use Apache2::ServerRec qw();
108 108 use Apache2::RequestRec qw();
109 109 use Apache2::RequestUtil qw();
110 110 use Apache2::Const qw(:common :override :cmd_how);
111 111
112 112 # use Apache2::Directive qw();
113 113
114 114 my @directives = (
115 115 {
116 116 name => 'RedmineDSN',
117 117 req_override => OR_AUTHCFG,
118 118 args_how => TAKE1,
119 119 errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
120 120 },
121 121 {
122 122 name => 'RedmineDbUser',
123 123 req_override => OR_AUTHCFG,
124 124 args_how => TAKE1,
125 125 },
126 126 {
127 127 name => 'RedmineDbPass',
128 128 req_override => OR_AUTHCFG,
129 129 args_how => TAKE1,
130 130 },
131 131 {
132 132 name => 'RedmineDbWhereClause',
133 133 req_override => OR_AUTHCFG,
134 134 args_how => TAKE1,
135 135 },
136 136 );
137 137
138 138 sub RedmineDSN { set_val('RedmineDSN', @_); }
139 139 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
140 140 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
141 141 sub RedmineDbWhereClause {
142 142 my ($self, $parms, $arg) = @_;
143 143 my $query = "SELECT
144 144 hashed_password, auth_source_id
145 145 FROM members, projects, users
146 146 WHERE
147 147 projects.id=members.project_id
148 148 AND users.id=members.user_id
149 149 AND users.status=1
150 150 AND login=?
151 151 AND identifier=? ";
152 152 $self->{RedmineQuery} = $query.($arg ? $arg : "").";";
153 153 }
154 154
155 155 sub set_val {
156 156 my ($key, $self, $parms, $arg) = @_;
157 157 $self->{$key} = $arg;
158 158 }
159 159
160 160 Apache2::Module::add(__PACKAGE__, \@directives);
161 161
162 162
163 163 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
164 164
165 165 sub access_handler {
166 166 my $r = shift;
167 167
168 168 unless ($r->some_auth_required) {
169 169 $r->log_reason("No authentication has been configured");
170 170 return FORBIDDEN;
171 171 }
172 172
173 173 my $method = $r->method;
174 174 return OK unless 1 == $read_only_methods{$method};
175 175
176 176 my $project_id = get_project_identifier($r);
177 177
178 178 $r->set_handlers(PerlAuthenHandler => [\&OK])
179 179 if is_public_project($project_id, $r);
180 180
181 181 return OK
182 182 }
183 183
184 184 sub authen_handler {
185 185 my $r = shift;
186 186
187 187 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
188 188 return $res unless $res == OK;
189 189
190 190 if (is_member($r->user, $redmine_pass, $r)) {
191 191 return OK;
192 192 } else {
193 193 $r->note_auth_failure();
194 194 return AUTH_REQUIRED;
195 195 }
196 196 }
197 197
198 198 sub is_public_project {
199 199 my $project_id = shift;
200 200 my $r = shift;
201 201
202 202 my $dbh = connect_database($r);
203 203 my $sth = $dbh->prepare(
204 204 "SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
205 205 );
206 206
207 207 $sth->execute($project_id);
208 208 my $ret = $sth->fetchrow_array ? 1 : 0;
209 209 $dbh->disconnect();
210 210
211 211 $ret;
212 212 }
213 213
214 214 # perhaps we should use repository right (other read right) to check public access.
215 215 # it could be faster BUT it doesn't work for the moment.
216 216 # sub is_public_project_by_file {
217 217 # my $project_id = shift;
218 218 # my $r = shift;
219 219
220 220 # my $tree = Apache2::Directive::conftree();
221 221 # my $node = $tree->lookup('Location', $r->location);
222 222 # my $hash = $node->as_hash;
223 223
224 224 # my $svnparentpath = $hash->{SVNParentPath};
225 225 # my $repos_path = $svnparentpath . "/" . $project_id;
226 226 # return 1 if (stat($repos_path))[2] & 00007;
227 227 # }
228 228
229 229 sub is_member {
230 230 my $redmine_user = shift;
231 231 my $redmine_pass = shift;
232 232 my $r = shift;
233 233
234 234 my $dbh = connect_database($r);
235 235 my $project_id = get_project_identifier($r);
236 236
237 237 my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
238 238
239 239 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
240 240 my $query = $cfg->{RedmineQuery};
241 241 my $sth = $dbh->prepare($query);
242 242 $sth->execute($redmine_user, $project_id);
243 243
244 244 my $ret;
245 245 while (my @row = $sth->fetchrow_array) {
246 246 unless ($row[1]) {
247 247 if ($row[0] eq $pass_digest) {
248 248 $ret = 1;
249 249 last;
250 250 }
251 251 } elsif ($CanUseLDAPAuth) {
252 252 my $sthldap = $dbh->prepare(
253 253 "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
254 254 );
255 255 $sthldap->execute($row[1]);
256 256 while (my @rowldap = $sthldap->fetchrow_array) {
257 257 my $ldap = Authen::Simple::LDAP->new(
258 258 host => ($rowldap[2] == 1 || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]" : $rowldap[0],
259 259 port => $rowldap[1],
260 260 basedn => $rowldap[5],
261 261 binddn => $rowldap[3] ? $rowldap[3] : "",
262 262 bindpw => $rowldap[4] ? $rowldap[4] : "",
263 263 filter => "(".$rowldap[6]."=%s)"
264 264 );
265 265 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass));
266 266 }
267 267 $sthldap->finish();
268 268 }
269 269 }
270 270 $sth->finish();
271 271 $dbh->disconnect();
272 272
273 273 $ret;
274 274 }
275 275
276 276 sub get_project_identifier {
277 277 my $r = shift;
278 278
279 279 my $location = $r->location;
280 280 my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
281 281 $identifier;
282 282 }
283 283
284 284 sub connect_database {
285 285 my $r = shift;
286 286
287 287 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
288 288 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
289 289 }
290 290
291 291 1;
General Comments 0
You need to be logged in to leave comments. Login now