##// END OF EJS Templates
Makes Redmine.pm work with multiple repositories per project (#779)....
Jean-Philippe Lang -
r9136:f071b39d268a
parent child
Show More
@@ -1,413 +1,422
1 package Apache::Authn::Redmine;
1 package Apache::Authn::Redmine;
2
2
3 =head1 Apache::Authn::Redmine
3 =head1 Apache::Authn::Redmine
4
4
5 Redmine - a mod_perl module to authenticate webdav subversion users
5 Redmine - a mod_perl module to authenticate webdav subversion users
6 against redmine database
6 against redmine database
7
7
8 =head1 SYNOPSIS
8 =head1 SYNOPSIS
9
9
10 This module allow anonymous users to browse public project and
10 This module allow anonymous users to browse public project and
11 registred users to browse and commit their project. Authentication is
11 registred users to browse and commit their project. Authentication is
12 done against the redmine database or the LDAP configured in redmine.
12 done against the redmine database or the LDAP configured in redmine.
13
13
14 This method is far simpler than the one with pam_* and works with all
14 This method is far simpler than the one with pam_* and works with all
15 database without an hassle but you need to have apache/mod_perl on the
15 database without an hassle but you need to have apache/mod_perl on the
16 svn server.
16 svn server.
17
17
18 =head1 INSTALLATION
18 =head1 INSTALLATION
19
19
20 For this to automagically work, you need to have a recent reposman.rb
20 For this to automagically work, you need to have a recent reposman.rb
21 (after r860) and if you already use reposman, read the last section to
21 (after r860) and if you already use reposman, read the last section to
22 migrate.
22 migrate.
23
23
24 Sorry ruby users but you need some perl modules, at least mod_perl2,
24 Sorry ruby users but you need some perl modules, at least mod_perl2,
25 DBI and DBD::mysql (or the DBD driver for you database as it should
25 DBI and DBD::mysql (or the DBD driver for you database as it should
26 work on allmost all databases).
26 work on allmost all databases).
27
27
28 On debian/ubuntu you must do :
28 On debian/ubuntu you must do :
29
29
30 aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
30 aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
31
31
32 If your Redmine users use LDAP authentication, you will also need
32 If your Redmine users use LDAP authentication, you will also need
33 Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
33 Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
34
34
35 aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl
35 aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl
36
36
37 =head1 CONFIGURATION
37 =head1 CONFIGURATION
38
38
39 ## This module has to be in your perl path
39 ## This module has to be in your perl path
40 ## eg: /usr/lib/perl5/Apache/Authn/Redmine.pm
40 ## eg: /usr/lib/perl5/Apache/Authn/Redmine.pm
41 PerlLoadModule Apache::Authn::Redmine
41 PerlLoadModule Apache::Authn::Redmine
42 <Location /svn>
42 <Location /svn>
43 DAV svn
43 DAV svn
44 SVNParentPath "/var/svn"
44 SVNParentPath "/var/svn"
45
45
46 AuthType Basic
46 AuthType Basic
47 AuthName redmine
47 AuthName redmine
48 Require valid-user
48 Require valid-user
49
49
50 PerlAccessHandler Apache::Authn::Redmine::access_handler
50 PerlAccessHandler Apache::Authn::Redmine::access_handler
51 PerlAuthenHandler Apache::Authn::Redmine::authen_handler
51 PerlAuthenHandler Apache::Authn::Redmine::authen_handler
52
52
53 ## for mysql
53 ## for mysql
54 RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
54 RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
55 ## for postgres
55 ## for postgres
56 # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server"
56 # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server"
57
57
58 RedmineDbUser "redmine"
58 RedmineDbUser "redmine"
59 RedmineDbPass "password"
59 RedmineDbPass "password"
60 ## Optional where clause (fulltext search would be slow and
60 ## Optional where clause (fulltext search would be slow and
61 ## database dependant).
61 ## database dependant).
62 # RedmineDbWhereClause "and members.role_id IN (1,2)"
62 # RedmineDbWhereClause "and members.role_id IN (1,2)"
63 ## Optional credentials cache size
63 ## Optional credentials cache size
64 # RedmineCacheCredsMax 50
64 # RedmineCacheCredsMax 50
65 </Location>
65 </Location>
66
66
67 To be able to browse repository inside redmine, you must add something
67 To be able to browse repository inside redmine, you must add something
68 like that :
68 like that :
69
69
70 <Location /svn-private>
70 <Location /svn-private>
71 DAV svn
71 DAV svn
72 SVNParentPath "/var/svn"
72 SVNParentPath "/var/svn"
73 Order deny,allow
73 Order deny,allow
74 Deny from all
74 Deny from all
75 # only allow reading orders
75 # only allow reading orders
76 <Limit GET PROPFIND OPTIONS REPORT>
76 <Limit GET PROPFIND OPTIONS REPORT>
77 Allow from redmine.server.ip
77 Allow from redmine.server.ip
78 </Limit>
78 </Limit>
79 </Location>
79 </Location>
80
80
81 and you will have to use this reposman.rb command line to create repository :
81 and you will have to use this reposman.rb command line to create repository :
82
82
83 reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
83 reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
84
84
85 =head1 REPOSITORIES NAMING
86
87 A projet repository must be named with the projet identifier. In case
88 of multiple repositories for the same project, use the project identifier
89 and the repository identifier separated with a dot:
90
91 /var/svn/foo
92 /var/svn/foo.otherrepo
93
85 =head1 MIGRATION FROM OLDER RELEASES
94 =head1 MIGRATION FROM OLDER RELEASES
86
95
87 If you use an older reposman.rb (r860 or before), you need to change
96 If you use an older reposman.rb (r860 or before), you need to change
88 rights on repositories to allow the apache user to read and write
97 rights on repositories to allow the apache user to read and write
89 S<them :>
98 S<them :>
90
99
91 sudo chown -R www-data /var/svn/*
100 sudo chown -R www-data /var/svn/*
92 sudo chmod -R u+w /var/svn/*
101 sudo chmod -R u+w /var/svn/*
93
102
94 And you need to upgrade at least reposman.rb (after r860).
103 And you need to upgrade at least reposman.rb (after r860).
95
104
96 =cut
105 =cut
97
106
98 use strict;
107 use strict;
99 use warnings FATAL => 'all', NONFATAL => 'redefine';
108 use warnings FATAL => 'all', NONFATAL => 'redefine';
100
109
101 use DBI;
110 use DBI;
102 use Digest::SHA;
111 use Digest::SHA;
103 # optional module for LDAP authentication
112 # optional module for LDAP authentication
104 my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
113 my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
105
114
106 use Apache2::Module;
115 use Apache2::Module;
107 use Apache2::Access;
116 use Apache2::Access;
108 use Apache2::ServerRec qw();
117 use Apache2::ServerRec qw();
109 use Apache2::RequestRec qw();
118 use Apache2::RequestRec qw();
110 use Apache2::RequestUtil qw();
119 use Apache2::RequestUtil qw();
111 use Apache2::Const qw(:common :override :cmd_how);
120 use Apache2::Const qw(:common :override :cmd_how);
112 use APR::Pool ();
121 use APR::Pool ();
113 use APR::Table ();
122 use APR::Table ();
114
123
115 # use Apache2::Directive qw();
124 # use Apache2::Directive qw();
116
125
117 my @directives = (
126 my @directives = (
118 {
127 {
119 name => 'RedmineDSN',
128 name => 'RedmineDSN',
120 req_override => OR_AUTHCFG,
129 req_override => OR_AUTHCFG,
121 args_how => TAKE1,
130 args_how => TAKE1,
122 errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
131 errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
123 },
132 },
124 {
133 {
125 name => 'RedmineDbUser',
134 name => 'RedmineDbUser',
126 req_override => OR_AUTHCFG,
135 req_override => OR_AUTHCFG,
127 args_how => TAKE1,
136 args_how => TAKE1,
128 },
137 },
129 {
138 {
130 name => 'RedmineDbPass',
139 name => 'RedmineDbPass',
131 req_override => OR_AUTHCFG,
140 req_override => OR_AUTHCFG,
132 args_how => TAKE1,
141 args_how => TAKE1,
133 },
142 },
134 {
143 {
135 name => 'RedmineDbWhereClause',
144 name => 'RedmineDbWhereClause',
136 req_override => OR_AUTHCFG,
145 req_override => OR_AUTHCFG,
137 args_how => TAKE1,
146 args_how => TAKE1,
138 },
147 },
139 {
148 {
140 name => 'RedmineCacheCredsMax',
149 name => 'RedmineCacheCredsMax',
141 req_override => OR_AUTHCFG,
150 req_override => OR_AUTHCFG,
142 args_how => TAKE1,
151 args_how => TAKE1,
143 errmsg => 'RedmineCacheCredsMax must be decimal number',
152 errmsg => 'RedmineCacheCredsMax must be decimal number',
144 },
153 },
145 );
154 );
146
155
147 sub RedmineDSN {
156 sub RedmineDSN {
148 my ($self, $parms, $arg) = @_;
157 my ($self, $parms, $arg) = @_;
149 $self->{RedmineDSN} = $arg;
158 $self->{RedmineDSN} = $arg;
150 my $query = "SELECT
159 my $query = "SELECT
151 hashed_password, salt, auth_source_id, permissions
160 hashed_password, salt, auth_source_id, permissions
152 FROM projects, users, roles
161 FROM projects, users, roles
153 WHERE
162 WHERE
154 users.login=?
163 users.login=?
155 AND projects.identifier=?
164 AND projects.identifier=?
156 AND users.status=1
165 AND users.status=1
157 AND (
166 AND (
158 roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
167 roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
159 OR
168 OR
160 (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
169 (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
161 ) ";
170 ) ";
162 $self->{RedmineQuery} = trim($query);
171 $self->{RedmineQuery} = trim($query);
163 }
172 }
164
173
165 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
174 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
166 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
175 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
167 sub RedmineDbWhereClause {
176 sub RedmineDbWhereClause {
168 my ($self, $parms, $arg) = @_;
177 my ($self, $parms, $arg) = @_;
169 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
178 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
170 }
179 }
171
180
172 sub RedmineCacheCredsMax {
181 sub RedmineCacheCredsMax {
173 my ($self, $parms, $arg) = @_;
182 my ($self, $parms, $arg) = @_;
174 if ($arg) {
183 if ($arg) {
175 $self->{RedmineCachePool} = APR::Pool->new;
184 $self->{RedmineCachePool} = APR::Pool->new;
176 $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg);
185 $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg);
177 $self->{RedmineCacheCredsCount} = 0;
186 $self->{RedmineCacheCredsCount} = 0;
178 $self->{RedmineCacheCredsMax} = $arg;
187 $self->{RedmineCacheCredsMax} = $arg;
179 }
188 }
180 }
189 }
181
190
182 sub trim {
191 sub trim {
183 my $string = shift;
192 my $string = shift;
184 $string =~ s/\s{2,}/ /g;
193 $string =~ s/\s{2,}/ /g;
185 return $string;
194 return $string;
186 }
195 }
187
196
188 sub set_val {
197 sub set_val {
189 my ($key, $self, $parms, $arg) = @_;
198 my ($key, $self, $parms, $arg) = @_;
190 $self->{$key} = $arg;
199 $self->{$key} = $arg;
191 }
200 }
192
201
193 Apache2::Module::add(__PACKAGE__, \@directives);
202 Apache2::Module::add(__PACKAGE__, \@directives);
194
203
195
204
196 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
205 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
197
206
198 sub access_handler {
207 sub access_handler {
199 my $r = shift;
208 my $r = shift;
200
209
201 unless ($r->some_auth_required) {
210 unless ($r->some_auth_required) {
202 $r->log_reason("No authentication has been configured");
211 $r->log_reason("No authentication has been configured");
203 return FORBIDDEN;
212 return FORBIDDEN;
204 }
213 }
205
214
206 my $method = $r->method;
215 my $method = $r->method;
207 return OK unless defined $read_only_methods{$method};
216 return OK unless defined $read_only_methods{$method};
208
217
209 my $project_id = get_project_identifier($r);
218 my $project_id = get_project_identifier($r);
210
219
211 $r->set_handlers(PerlAuthenHandler => [\&OK])
220 $r->set_handlers(PerlAuthenHandler => [\&OK])
212 if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r);
221 if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r);
213
222
214 return OK
223 return OK
215 }
224 }
216
225
217 sub authen_handler {
226 sub authen_handler {
218 my $r = shift;
227 my $r = shift;
219
228
220 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
229 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
221 return $res unless $res == OK;
230 return $res unless $res == OK;
222
231
223 if (is_member($r->user, $redmine_pass, $r)) {
232 if (is_member($r->user, $redmine_pass, $r)) {
224 return OK;
233 return OK;
225 } else {
234 } else {
226 $r->note_auth_failure();
235 $r->note_auth_failure();
227 return AUTH_REQUIRED;
236 return AUTH_REQUIRED;
228 }
237 }
229 }
238 }
230
239
231 # check if authentication is forced
240 # check if authentication is forced
232 sub is_authentication_forced {
241 sub is_authentication_forced {
233 my $r = shift;
242 my $r = shift;
234
243
235 my $dbh = connect_database($r);
244 my $dbh = connect_database($r);
236 my $sth = $dbh->prepare(
245 my $sth = $dbh->prepare(
237 "SELECT value FROM settings where settings.name = 'login_required';"
246 "SELECT value FROM settings where settings.name = 'login_required';"
238 );
247 );
239
248
240 $sth->execute();
249 $sth->execute();
241 my $ret = 0;
250 my $ret = 0;
242 if (my @row = $sth->fetchrow_array) {
251 if (my @row = $sth->fetchrow_array) {
243 if ($row[0] eq "1" || $row[0] eq "t") {
252 if ($row[0] eq "1" || $row[0] eq "t") {
244 $ret = 1;
253 $ret = 1;
245 }
254 }
246 }
255 }
247 $sth->finish();
256 $sth->finish();
248 undef $sth;
257 undef $sth;
249
258
250 $dbh->disconnect();
259 $dbh->disconnect();
251 undef $dbh;
260 undef $dbh;
252
261
253 $ret;
262 $ret;
254 }
263 }
255
264
256 sub is_public_project {
265 sub is_public_project {
257 my $project_id = shift;
266 my $project_id = shift;
258 my $r = shift;
267 my $r = shift;
259
268
260 if (is_authentication_forced($r)) {
269 if (is_authentication_forced($r)) {
261 return 0;
270 return 0;
262 }
271 }
263
272
264 my $dbh = connect_database($r);
273 my $dbh = connect_database($r);
265 my $sth = $dbh->prepare(
274 my $sth = $dbh->prepare(
266 "SELECT is_public FROM projects WHERE projects.identifier = ?;"
275 "SELECT is_public FROM projects WHERE projects.identifier = ?;"
267 );
276 );
268
277
269 $sth->execute($project_id);
278 $sth->execute($project_id);
270 my $ret = 0;
279 my $ret = 0;
271 if (my @row = $sth->fetchrow_array) {
280 if (my @row = $sth->fetchrow_array) {
272 if ($row[0] eq "1" || $row[0] eq "t") {
281 if ($row[0] eq "1" || $row[0] eq "t") {
273 $ret = 1;
282 $ret = 1;
274 }
283 }
275 }
284 }
276 $sth->finish();
285 $sth->finish();
277 undef $sth;
286 undef $sth;
278 $dbh->disconnect();
287 $dbh->disconnect();
279 undef $dbh;
288 undef $dbh;
280
289
281 $ret;
290 $ret;
282 }
291 }
283
292
284 sub anonymous_role_allows_browse_repository {
293 sub anonymous_role_allows_browse_repository {
285 my $r = shift;
294 my $r = shift;
286
295
287 my $dbh = connect_database($r);
296 my $dbh = connect_database($r);
288 my $sth = $dbh->prepare(
297 my $sth = $dbh->prepare(
289 "SELECT permissions FROM roles WHERE builtin = 2;"
298 "SELECT permissions FROM roles WHERE builtin = 2;"
290 );
299 );
291
300
292 $sth->execute();
301 $sth->execute();
293 my $ret = 0;
302 my $ret = 0;
294 if (my @row = $sth->fetchrow_array) {
303 if (my @row = $sth->fetchrow_array) {
295 if ($row[0] =~ /:browse_repository/) {
304 if ($row[0] =~ /:browse_repository/) {
296 $ret = 1;
305 $ret = 1;
297 }
306 }
298 }
307 }
299 $sth->finish();
308 $sth->finish();
300 undef $sth;
309 undef $sth;
301 $dbh->disconnect();
310 $dbh->disconnect();
302 undef $dbh;
311 undef $dbh;
303
312
304 $ret;
313 $ret;
305 }
314 }
306
315
307 # perhaps we should use repository right (other read right) to check public access.
316 # perhaps we should use repository right (other read right) to check public access.
308 # it could be faster BUT it doesn't work for the moment.
317 # it could be faster BUT it doesn't work for the moment.
309 # sub is_public_project_by_file {
318 # sub is_public_project_by_file {
310 # my $project_id = shift;
319 # my $project_id = shift;
311 # my $r = shift;
320 # my $r = shift;
312
321
313 # my $tree = Apache2::Directive::conftree();
322 # my $tree = Apache2::Directive::conftree();
314 # my $node = $tree->lookup('Location', $r->location);
323 # my $node = $tree->lookup('Location', $r->location);
315 # my $hash = $node->as_hash;
324 # my $hash = $node->as_hash;
316
325
317 # my $svnparentpath = $hash->{SVNParentPath};
326 # my $svnparentpath = $hash->{SVNParentPath};
318 # my $repos_path = $svnparentpath . "/" . $project_id;
327 # my $repos_path = $svnparentpath . "/" . $project_id;
319 # return 1 if (stat($repos_path))[2] & 00007;
328 # return 1 if (stat($repos_path))[2] & 00007;
320 # }
329 # }
321
330
322 sub is_member {
331 sub is_member {
323 my $redmine_user = shift;
332 my $redmine_user = shift;
324 my $redmine_pass = shift;
333 my $redmine_pass = shift;
325 my $r = shift;
334 my $r = shift;
326
335
327 my $dbh = connect_database($r);
336 my $dbh = connect_database($r);
328 my $project_id = get_project_identifier($r);
337 my $project_id = get_project_identifier($r);
329
338
330 my $pass_digest = Digest::SHA::sha1_hex($redmine_pass);
339 my $pass_digest = Digest::SHA::sha1_hex($redmine_pass);
331
340
332 my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
341 my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
333
342
334 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
343 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
335 my $usrprojpass;
344 my $usrprojpass;
336 if ($cfg->{RedmineCacheCredsMax}) {
345 if ($cfg->{RedmineCacheCredsMax}) {
337 $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
346 $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
338 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
347 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
339 }
348 }
340 my $query = $cfg->{RedmineQuery};
349 my $query = $cfg->{RedmineQuery};
341 my $sth = $dbh->prepare($query);
350 my $sth = $dbh->prepare($query);
342 $sth->execute($redmine_user, $project_id);
351 $sth->execute($redmine_user, $project_id);
343
352
344 my $ret;
353 my $ret;
345 while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) {
354 while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) {
346
355
347 unless ($auth_source_id) {
356 unless ($auth_source_id) {
348 my $method = $r->method;
357 my $method = $r->method;
349 my $salted_password = Digest::SHA::sha1_hex($salt.$pass_digest);
358 my $salted_password = Digest::SHA::sha1_hex($salt.$pass_digest);
350 if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
359 if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
351 $ret = 1;
360 $ret = 1;
352 last;
361 last;
353 }
362 }
354 } elsif ($CanUseLDAPAuth) {
363 } elsif ($CanUseLDAPAuth) {
355 my $sthldap = $dbh->prepare(
364 my $sthldap = $dbh->prepare(
356 "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
365 "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
357 );
366 );
358 $sthldap->execute($auth_source_id);
367 $sthldap->execute($auth_source_id);
359 while (my @rowldap = $sthldap->fetchrow_array) {
368 while (my @rowldap = $sthldap->fetchrow_array) {
360 my $ldap = Authen::Simple::LDAP->new(
369 my $ldap = Authen::Simple::LDAP->new(
361 host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0],
370 host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0],
362 port => $rowldap[1],
371 port => $rowldap[1],
363 basedn => $rowldap[5],
372 basedn => $rowldap[5],
364 binddn => $rowldap[3] ? $rowldap[3] : "",
373 binddn => $rowldap[3] ? $rowldap[3] : "",
365 bindpw => $rowldap[4] ? $rowldap[4] : "",
374 bindpw => $rowldap[4] ? $rowldap[4] : "",
366 filter => "(".$rowldap[6]."=%s)"
375 filter => "(".$rowldap[6]."=%s)"
367 );
376 );
368 my $method = $r->method;
377 my $method = $r->method;
369 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
378 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
370
379
371 }
380 }
372 $sthldap->finish();
381 $sthldap->finish();
373 undef $sthldap;
382 undef $sthldap;
374 }
383 }
375 }
384 }
376 $sth->finish();
385 $sth->finish();
377 undef $sth;
386 undef $sth;
378 $dbh->disconnect();
387 $dbh->disconnect();
379 undef $dbh;
388 undef $dbh;
380
389
381 if ($cfg->{RedmineCacheCredsMax} and $ret) {
390 if ($cfg->{RedmineCacheCredsMax} and $ret) {
382 if (defined $usrprojpass) {
391 if (defined $usrprojpass) {
383 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
392 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
384 } else {
393 } else {
385 if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
394 if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
386 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
395 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
387 $cfg->{RedmineCacheCredsCount}++;
396 $cfg->{RedmineCacheCredsCount}++;
388 } else {
397 } else {
389 $cfg->{RedmineCacheCreds}->clear();
398 $cfg->{RedmineCacheCreds}->clear();
390 $cfg->{RedmineCacheCredsCount} = 0;
399 $cfg->{RedmineCacheCredsCount} = 0;
391 }
400 }
392 }
401 }
393 }
402 }
394
403
395 $ret;
404 $ret;
396 }
405 }
397
406
398 sub get_project_identifier {
407 sub get_project_identifier {
399 my $r = shift;
408 my $r = shift;
400
409
401 my $location = $r->location;
410 my $location = $r->location;
402 my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
411 my ($identifier) = $r->uri =~ m{$location/*([^/.]+)};
403 $identifier;
412 $identifier;
404 }
413 }
405
414
406 sub connect_database {
415 sub connect_database {
407 my $r = shift;
416 my $r = shift;
408
417
409 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
418 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
410 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
419 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
411 }
420 }
412
421
413 1;
422 1;
General Comments 0
You need to be logged in to leave comments. Login now