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