##// END OF EJS Templates
Merged r7809 from trunk (#9567)....
Jean-Philippe Lang -
r8000:40a14cafbc3f
parent child
Show More
@@ -1,411 +1,413
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 MIGRATION FROM OLDER RELEASES
85 =head1 MIGRATION FROM OLDER RELEASES
86
86
87 If you use an older reposman.rb (r860 or before), you need to change
87 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
88 rights on repositories to allow the apache user to read and write
89 S<them :>
89 S<them :>
90
90
91 sudo chown -R www-data /var/svn/*
91 sudo chown -R www-data /var/svn/*
92 sudo chmod -R u+w /var/svn/*
92 sudo chmod -R u+w /var/svn/*
93
93
94 And you need to upgrade at least reposman.rb (after r860).
94 And you need to upgrade at least reposman.rb (after r860).
95
95
96 =cut
96 =cut
97
97
98 use strict;
98 use strict;
99 use warnings FATAL => 'all', NONFATAL => 'redefine';
99 use warnings FATAL => 'all', NONFATAL => 'redefine';
100
100
101 use DBI;
101 use DBI;
102 use Digest::SHA1;
102 use Digest::SHA1;
103 # optional module for LDAP authentication
103 # optional module for LDAP authentication
104 my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
104 my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
105
105
106 use Apache2::Module;
106 use Apache2::Module;
107 use Apache2::Access;
107 use Apache2::Access;
108 use Apache2::ServerRec qw();
108 use Apache2::ServerRec qw();
109 use Apache2::RequestRec qw();
109 use Apache2::RequestRec qw();
110 use Apache2::RequestUtil qw();
110 use Apache2::RequestUtil qw();
111 use Apache2::Const qw(:common :override :cmd_how);
111 use Apache2::Const qw(:common :override :cmd_how);
112 use APR::Pool ();
112 use APR::Pool ();
113 use APR::Table ();
113 use APR::Table ();
114
114
115 # use Apache2::Directive qw();
115 # use Apache2::Directive qw();
116
116
117 my @directives = (
117 my @directives = (
118 {
118 {
119 name => 'RedmineDSN',
119 name => 'RedmineDSN',
120 req_override => OR_AUTHCFG,
120 req_override => OR_AUTHCFG,
121 args_how => TAKE1,
121 args_how => TAKE1,
122 errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
122 errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
123 },
123 },
124 {
124 {
125 name => 'RedmineDbUser',
125 name => 'RedmineDbUser',
126 req_override => OR_AUTHCFG,
126 req_override => OR_AUTHCFG,
127 args_how => TAKE1,
127 args_how => TAKE1,
128 },
128 },
129 {
129 {
130 name => 'RedmineDbPass',
130 name => 'RedmineDbPass',
131 req_override => OR_AUTHCFG,
131 req_override => OR_AUTHCFG,
132 args_how => TAKE1,
132 args_how => TAKE1,
133 },
133 },
134 {
134 {
135 name => 'RedmineDbWhereClause',
135 name => 'RedmineDbWhereClause',
136 req_override => OR_AUTHCFG,
136 req_override => OR_AUTHCFG,
137 args_how => TAKE1,
137 args_how => TAKE1,
138 },
138 },
139 {
139 {
140 name => 'RedmineCacheCredsMax',
140 name => 'RedmineCacheCredsMax',
141 req_override => OR_AUTHCFG,
141 req_override => OR_AUTHCFG,
142 args_how => TAKE1,
142 args_how => TAKE1,
143 errmsg => 'RedmineCacheCredsMax must be decimal number',
143 errmsg => 'RedmineCacheCredsMax must be decimal number',
144 },
144 },
145 );
145 );
146
146
147 sub RedmineDSN {
147 sub RedmineDSN {
148 my ($self, $parms, $arg) = @_;
148 my ($self, $parms, $arg) = @_;
149 $self->{RedmineDSN} = $arg;
149 $self->{RedmineDSN} = $arg;
150 my $query = "SELECT
150 my $query = "SELECT
151 hashed_password, salt, auth_source_id, permissions
151 hashed_password, salt, auth_source_id, permissions
152 FROM projects, users, roles
152 FROM projects, users, roles
153 WHERE
153 WHERE
154 users.login=?
154 users.login=?
155 AND projects.identifier=?
155 AND projects.identifier=?
156 AND users.status=1
156 AND users.status=1
157 AND (
157 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)
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)
159 OR
159 OR
160 (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
160 (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
161 ) ";
161 ) ";
162 $self->{RedmineQuery} = trim($query);
162 $self->{RedmineQuery} = trim($query);
163 }
163 }
164
164
165 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
165 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
166 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
166 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
167 sub RedmineDbWhereClause {
167 sub RedmineDbWhereClause {
168 my ($self, $parms, $arg) = @_;
168 my ($self, $parms, $arg) = @_;
169 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
169 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
170 }
170 }
171
171
172 sub RedmineCacheCredsMax {
172 sub RedmineCacheCredsMax {
173 my ($self, $parms, $arg) = @_;
173 my ($self, $parms, $arg) = @_;
174 if ($arg) {
174 if ($arg) {
175 $self->{RedmineCachePool} = APR::Pool->new;
175 $self->{RedmineCachePool} = APR::Pool->new;
176 $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg);
176 $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg);
177 $self->{RedmineCacheCredsCount} = 0;
177 $self->{RedmineCacheCredsCount} = 0;
178 $self->{RedmineCacheCredsMax} = $arg;
178 $self->{RedmineCacheCredsMax} = $arg;
179 }
179 }
180 }
180 }
181
181
182 sub trim {
182 sub trim {
183 my $string = shift;
183 my $string = shift;
184 $string =~ s/\s{2,}/ /g;
184 $string =~ s/\s{2,}/ /g;
185 return $string;
185 return $string;
186 }
186 }
187
187
188 sub set_val {
188 sub set_val {
189 my ($key, $self, $parms, $arg) = @_;
189 my ($key, $self, $parms, $arg) = @_;
190 $self->{$key} = $arg;
190 $self->{$key} = $arg;
191 }
191 }
192
192
193 Apache2::Module::add(__PACKAGE__, \@directives);
193 Apache2::Module::add(__PACKAGE__, \@directives);
194
194
195
195
196 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
196 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
197
197
198 sub access_handler {
198 sub access_handler {
199 my $r = shift;
199 my $r = shift;
200
200
201 unless ($r->some_auth_required) {
201 unless ($r->some_auth_required) {
202 $r->log_reason("No authentication has been configured");
202 $r->log_reason("No authentication has been configured");
203 return FORBIDDEN;
203 return FORBIDDEN;
204 }
204 }
205
205
206 my $method = $r->method;
206 my $method = $r->method;
207 return OK unless defined $read_only_methods{$method};
207 return OK unless defined $read_only_methods{$method};
208
208
209 my $project_id = get_project_identifier($r);
209 my $project_id = get_project_identifier($r);
210
210
211 $r->set_handlers(PerlAuthenHandler => [\&OK])
211 $r->set_handlers(PerlAuthenHandler => [\&OK])
212 if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r);
212 if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r);
213
213
214 return OK
214 return OK
215 }
215 }
216
216
217 sub authen_handler {
217 sub authen_handler {
218 my $r = shift;
218 my $r = shift;
219
219
220 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
220 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
221 return $res unless $res == OK;
221 return $res unless $res == OK;
222
222
223 if (is_member($r->user, $redmine_pass, $r)) {
223 if (is_member($r->user, $redmine_pass, $r)) {
224 return OK;
224 return OK;
225 } else {
225 } else {
226 $r->note_auth_failure();
226 $r->note_auth_failure();
227 return AUTH_REQUIRED;
227 return AUTH_REQUIRED;
228 }
228 }
229 }
229 }
230
230
231 # check if authentication is forced
231 # check if authentication is forced
232 sub is_authentication_forced {
232 sub is_authentication_forced {
233 my $r = shift;
233 my $r = shift;
234
234
235 my $dbh = connect_database($r);
235 my $dbh = connect_database($r);
236 my $sth = $dbh->prepare(
236 my $sth = $dbh->prepare(
237 "SELECT value FROM settings where settings.name = 'login_required';"
237 "SELECT value FROM settings where settings.name = 'login_required';"
238 );
238 );
239
239
240 $sth->execute();
240 $sth->execute();
241 my $ret = 0;
241 my $ret = 0;
242 if (my @row = $sth->fetchrow_array) {
242 if (my @row = $sth->fetchrow_array) {
243 if ($row[0] eq "1" || $row[0] eq "t") {
243 if ($row[0] eq "1" || $row[0] eq "t") {
244 $ret = 1;
244 $ret = 1;
245 }
245 }
246 }
246 }
247 $sth->finish();
247 $sth->finish();
248 undef $sth;
248 undef $sth;
249
249
250 $dbh->disconnect();
250 $dbh->disconnect();
251 undef $dbh;
251 undef $dbh;
252
252
253 $ret;
253 $ret;
254 }
254 }
255
255
256 sub is_public_project {
256 sub is_public_project {
257 my $project_id = shift;
257 my $project_id = shift;
258 my $r = shift;
258 my $r = shift;
259
259
260 if (is_authentication_forced($r)) {
260 if (is_authentication_forced($r)) {
261 return 0;
261 return 0;
262 }
262 }
263
263
264 my $dbh = connect_database($r);
264 my $dbh = connect_database($r);
265 my $sth = $dbh->prepare(
265 my $sth = $dbh->prepare(
266 "SELECT is_public FROM projects WHERE projects.identifier = ?;"
266 "SELECT is_public FROM projects WHERE projects.identifier = ?;"
267 );
267 );
268
268
269 $sth->execute($project_id);
269 $sth->execute($project_id);
270 my $ret = 0;
270 my $ret = 0;
271 if (my @row = $sth->fetchrow_array) {
271 if (my @row = $sth->fetchrow_array) {
272 if ($row[0] eq "1" || $row[0] eq "t") {
272 if ($row[0] eq "1" || $row[0] eq "t") {
273 $ret = 1;
273 $ret = 1;
274 }
274 }
275 }
275 }
276 $sth->finish();
276 $sth->finish();
277 undef $sth;
277 undef $sth;
278 $dbh->disconnect();
278 $dbh->disconnect();
279 undef $dbh;
279 undef $dbh;
280
280
281 $ret;
281 $ret;
282 }
282 }
283
283
284 sub anonymous_role_allows_browse_repository {
284 sub anonymous_role_allows_browse_repository {
285 my $r = shift;
285 my $r = shift;
286
286
287 my $dbh = connect_database($r);
287 my $dbh = connect_database($r);
288 my $sth = $dbh->prepare(
288 my $sth = $dbh->prepare(
289 "SELECT permissions FROM roles WHERE builtin = 2;"
289 "SELECT permissions FROM roles WHERE builtin = 2;"
290 );
290 );
291
291
292 $sth->execute();
292 $sth->execute();
293 my $ret = 0;
293 my $ret = 0;
294 if (my @row = $sth->fetchrow_array) {
294 if (my @row = $sth->fetchrow_array) {
295 if ($row[0] =~ /:browse_repository/) {
295 if ($row[0] =~ /:browse_repository/) {
296 $ret = 1;
296 $ret = 1;
297 }
297 }
298 }
298 }
299 $sth->finish();
299 $sth->finish();
300 undef $sth;
300 undef $sth;
301 $dbh->disconnect();
301 $dbh->disconnect();
302 undef $dbh;
302 undef $dbh;
303
303
304 $ret;
304 $ret;
305 }
305 }
306
306
307 # perhaps we should use repository right (other read right) to check public access.
307 # 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.
308 # it could be faster BUT it doesn't work for the moment.
309 # sub is_public_project_by_file {
309 # sub is_public_project_by_file {
310 # my $project_id = shift;
310 # my $project_id = shift;
311 # my $r = shift;
311 # my $r = shift;
312
312
313 # my $tree = Apache2::Directive::conftree();
313 # my $tree = Apache2::Directive::conftree();
314 # my $node = $tree->lookup('Location', $r->location);
314 # my $node = $tree->lookup('Location', $r->location);
315 # my $hash = $node->as_hash;
315 # my $hash = $node->as_hash;
316
316
317 # my $svnparentpath = $hash->{SVNParentPath};
317 # my $svnparentpath = $hash->{SVNParentPath};
318 # my $repos_path = $svnparentpath . "/" . $project_id;
318 # my $repos_path = $svnparentpath . "/" . $project_id;
319 # return 1 if (stat($repos_path))[2] & 00007;
319 # return 1 if (stat($repos_path))[2] & 00007;
320 # }
320 # }
321
321
322 sub is_member {
322 sub is_member {
323 my $redmine_user = shift;
323 my $redmine_user = shift;
324 my $redmine_pass = shift;
324 my $redmine_pass = shift;
325 my $r = shift;
325 my $r = shift;
326
326
327 my $dbh = connect_database($r);
327 my $dbh = connect_database($r);
328 my $project_id = get_project_identifier($r);
328 my $project_id = get_project_identifier($r);
329
329
330 my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
330 my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
331
332 my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
331
333
332 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
334 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
333 my $usrprojpass;
335 my $usrprojpass;
334 if ($cfg->{RedmineCacheCredsMax}) {
336 if ($cfg->{RedmineCacheCredsMax}) {
335 $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id);
337 $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
336 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
338 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
337 }
339 }
338 my $query = $cfg->{RedmineQuery};
340 my $query = $cfg->{RedmineQuery};
339 my $sth = $dbh->prepare($query);
341 my $sth = $dbh->prepare($query);
340 $sth->execute($redmine_user, $project_id);
342 $sth->execute($redmine_user, $project_id);
341
343
342 my $ret;
344 my $ret;
343 while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) {
345 while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) {
344
346
345 unless ($auth_source_id) {
347 unless ($auth_source_id) {
346 my $method = $r->method;
348 my $method = $r->method;
347 my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
349 my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
348 if ($hashed_password eq $salted_password && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
350 if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
349 $ret = 1;
351 $ret = 1;
350 last;
352 last;
351 }
353 }
352 } elsif ($CanUseLDAPAuth) {
354 } elsif ($CanUseLDAPAuth) {
353 my $sthldap = $dbh->prepare(
355 my $sthldap = $dbh->prepare(
354 "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
356 "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
355 );
357 );
356 $sthldap->execute($auth_source_id);
358 $sthldap->execute($auth_source_id);
357 while (my @rowldap = $sthldap->fetchrow_array) {
359 while (my @rowldap = $sthldap->fetchrow_array) {
358 my $ldap = Authen::Simple::LDAP->new(
360 my $ldap = Authen::Simple::LDAP->new(
359 host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0],
361 host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0],
360 port => $rowldap[1],
362 port => $rowldap[1],
361 basedn => $rowldap[5],
363 basedn => $rowldap[5],
362 binddn => $rowldap[3] ? $rowldap[3] : "",
364 binddn => $rowldap[3] ? $rowldap[3] : "",
363 bindpw => $rowldap[4] ? $rowldap[4] : "",
365 bindpw => $rowldap[4] ? $rowldap[4] : "",
364 filter => "(".$rowldap[6]."=%s)"
366 filter => "(".$rowldap[6]."=%s)"
365 );
367 );
366 my $method = $r->method;
368 my $method = $r->method;
367 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
369 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
368
370
369 }
371 }
370 $sthldap->finish();
372 $sthldap->finish();
371 undef $sthldap;
373 undef $sthldap;
372 }
374 }
373 }
375 }
374 $sth->finish();
376 $sth->finish();
375 undef $sth;
377 undef $sth;
376 $dbh->disconnect();
378 $dbh->disconnect();
377 undef $dbh;
379 undef $dbh;
378
380
379 if ($cfg->{RedmineCacheCredsMax} and $ret) {
381 if ($cfg->{RedmineCacheCredsMax} and $ret) {
380 if (defined $usrprojpass) {
382 if (defined $usrprojpass) {
381 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
383 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
382 } else {
384 } else {
383 if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
385 if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
384 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
386 $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
385 $cfg->{RedmineCacheCredsCount}++;
387 $cfg->{RedmineCacheCredsCount}++;
386 } else {
388 } else {
387 $cfg->{RedmineCacheCreds}->clear();
389 $cfg->{RedmineCacheCreds}->clear();
388 $cfg->{RedmineCacheCredsCount} = 0;
390 $cfg->{RedmineCacheCredsCount} = 0;
389 }
391 }
390 }
392 }
391 }
393 }
392
394
393 $ret;
395 $ret;
394 }
396 }
395
397
396 sub get_project_identifier {
398 sub get_project_identifier {
397 my $r = shift;
399 my $r = shift;
398
400
399 my $location = $r->location;
401 my $location = $r->location;
400 my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
402 my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
401 $identifier;
403 $identifier;
402 }
404 }
403
405
404 sub connect_database {
406 sub connect_database {
405 my $r = shift;
407 my $r = shift;
406
408
407 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
409 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
408 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
410 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
409 }
411 }
410
412
411 1;
413 1;
General Comments 0
You need to be logged in to leave comments. Login now