@@ -36,10 +36,9 Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used): | |||||
36 |
|
36 | |||
37 | =head1 CONFIGURATION |
|
37 | =head1 CONFIGURATION | |
38 |
|
38 | |||
39 |
## |
|
39 | ## This module has to be in your perl path | |
40 |
|
|
40 | ## eg: /usr/lib/perl5/Apache/Authn/Redmine.pm | |
41 | ## else |
|
41 | PerlLoadModule Apache::Authn::Redmine | |
42 | # PerlModule Apache::Authn::Redmine |
|
|||
43 | <Location /svn> |
|
42 | <Location /svn> | |
44 | DAV svn |
|
43 | DAV svn | |
45 | SVNParentPath "/var/svn" |
|
44 | SVNParentPath "/var/svn" | |
@@ -52,12 +51,17 Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used): | |||||
52 | PerlAuthenHandler Apache::Authn::Redmine::authen_handler |
|
51 | PerlAuthenHandler Apache::Authn::Redmine::authen_handler | |
53 |
|
52 | |||
54 | ## for mysql |
|
53 | ## for mysql | |
55 |
|
|
54 | RedmineDSN "DBI:mysql:database=databasename;host=my.db.server" | |
56 | ## for postgres |
|
55 | ## for postgres (there is memory leak in libpq+ssl) | |
57 |
# |
|
56 | # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server;sslmode=disable" | |
58 |
|
57 | |||
59 |
|
|
58 | RedmineDbUser "redmine" | |
60 | PerlSetVar db_pass password |
|
59 | RedmineDbPass "password" | |
|
60 | ## Optional where clause (fulltext search would be slow and | |||
|
61 | ## database dependant). | |||
|
62 | # RedmineDbWhereClause "and members.role_id IN (1,2)" | |||
|
63 | ## Optional credentials cache size | |||
|
64 | # RedmineCacheCredsMax 50 | |||
61 | </Location> |
|
65 | </Location> | |
62 |
|
66 | |||
63 | 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 | |
@@ -92,6 +96,7 And you need to upgrade at least reposman.rb (after r860). | |||||
92 | =cut |
|
96 | =cut | |
93 |
|
97 | |||
94 | use strict; |
|
98 | use strict; | |
|
99 | use warnings FATAL => 'all', NONFATAL => 'redefine'; | |||
95 |
|
100 | |||
96 | use DBI; |
|
101 | use DBI; | |
97 | use Digest::SHA1; |
|
102 | use Digest::SHA1; | |
@@ -103,9 +108,87 use Apache2::Access; | |||||
103 | use Apache2::ServerRec qw(); |
|
108 | use Apache2::ServerRec qw(); | |
104 | use Apache2::RequestRec qw(); |
|
109 | use Apache2::RequestRec qw(); | |
105 | use Apache2::RequestUtil qw(); |
|
110 | use Apache2::RequestUtil qw(); | |
106 | use Apache2::Const qw(:common); |
|
111 | use Apache2::Const qw(:common :override :cmd_how); | |
|
112 | use APR::Pool (); | |||
|
113 | use APR::Table (); | |||
|
114 | ||||
107 | # use Apache2::Directive qw(); |
|
115 | # use Apache2::Directive qw(); | |
108 |
|
116 | |||
|
117 | my @directives = ( | |||
|
118 | { | |||
|
119 | name => 'RedmineDSN', | |||
|
120 | req_override => OR_AUTHCFG, | |||
|
121 | args_how => TAKE1, | |||
|
122 | errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"', | |||
|
123 | }, | |||
|
124 | { | |||
|
125 | name => 'RedmineDbUser', | |||
|
126 | req_override => OR_AUTHCFG, | |||
|
127 | args_how => TAKE1, | |||
|
128 | }, | |||
|
129 | { | |||
|
130 | name => 'RedmineDbPass', | |||
|
131 | req_override => OR_AUTHCFG, | |||
|
132 | args_how => TAKE1, | |||
|
133 | }, | |||
|
134 | { | |||
|
135 | name => 'RedmineDbWhereClause', | |||
|
136 | req_override => OR_AUTHCFG, | |||
|
137 | args_how => TAKE1, | |||
|
138 | }, | |||
|
139 | { | |||
|
140 | name => 'RedmineCacheCredsMax', | |||
|
141 | req_override => OR_AUTHCFG, | |||
|
142 | args_how => TAKE1, | |||
|
143 | errmsg => 'RedmineCacheCredsMax must be decimal number', | |||
|
144 | }, | |||
|
145 | ); | |||
|
146 | ||||
|
147 | sub RedmineDSN { | |||
|
148 | my ($self, $parms, $arg) = @_; | |||
|
149 | $self->{RedmineDSN} = $arg; | |||
|
150 | my $query = "SELECT | |||
|
151 | hashed_password, auth_source_id | |||
|
152 | FROM members, projects, users | |||
|
153 | WHERE | |||
|
154 | projects.id=members.project_id | |||
|
155 | AND users.id=members.user_id | |||
|
156 | AND users.status=1 | |||
|
157 | AND login=? | |||
|
158 | AND identifier=? "; | |||
|
159 | $self->{RedmineQuery} = trim($query); | |||
|
160 | } | |||
|
161 | sub RedmineDbUser { set_val('RedmineDbUser', @_); } | |||
|
162 | sub RedmineDbPass { set_val('RedmineDbPass', @_); } | |||
|
163 | sub RedmineDbWhereClause { | |||
|
164 | my ($self, $parms, $arg) = @_; | |||
|
165 | $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." "); | |||
|
166 | } | |||
|
167 | ||||
|
168 | sub RedmineCacheCredsMax { | |||
|
169 | my ($self, $parms, $arg) = @_; | |||
|
170 | if ($arg) { | |||
|
171 | $self->{RedmineCachePool} = APR::Pool->new; | |||
|
172 | $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg); | |||
|
173 | $self->{RedmineCacheCredsCount} = 0; | |||
|
174 | $self->{RedmineCacheCredsMax} = $arg; | |||
|
175 | } | |||
|
176 | } | |||
|
177 | ||||
|
178 | sub trim { | |||
|
179 | my $string = shift; | |||
|
180 | $string =~ s/\s{2,}/ /g; | |||
|
181 | return $string; | |||
|
182 | } | |||
|
183 | ||||
|
184 | sub set_val { | |||
|
185 | my ($key, $self, $parms, $arg) = @_; | |||
|
186 | $self->{$key} = $arg; | |||
|
187 | } | |||
|
188 | ||||
|
189 | Apache2::Module::add(__PACKAGE__, \@directives); | |||
|
190 | ||||
|
191 | ||||
109 | my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/; |
|
192 | my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/; | |
110 |
|
193 | |||
111 | sub access_handler { |
|
194 | sub access_handler { | |
@@ -117,7 +200,7 sub access_handler { | |||||
117 | } |
|
200 | } | |
118 |
|
201 | |||
119 | my $method = $r->method; |
|
202 | my $method = $r->method; | |
120 |
return OK |
|
203 | return OK if defined $read_only_methods{$method}; | |
121 |
|
204 | |||
122 | my $project_id = get_project_identifier($r); |
|
205 | my $project_id = get_project_identifier($r); | |
123 |
|
206 | |||
@@ -182,9 +265,14 sub is_member { | |||||
182 |
|
265 | |||
183 | my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); |
|
266 | my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); | |
184 |
|
267 | |||
185 | my $sth = $dbh->prepare( |
|
268 | my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); | |
186 | "SELECT hashed_password, auth_source_id FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND users.status=1 AND login=? AND identifier=?;" |
|
269 | my $usrprojpass; | |
187 | ); |
|
270 | if ($cfg->{RedmineCacheCredsMax}) { | |
|
271 | $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id); | |||
|
272 | return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest)); | |||
|
273 | } | |||
|
274 | my $query = $cfg->{RedmineQuery}; | |||
|
275 | my $sth = $dbh->prepare($query); | |||
188 | $sth->execute($redmine_user, $project_id); |
|
276 | $sth->execute($redmine_user, $project_id); | |
189 |
|
277 | |||
190 | my $ret; |
|
278 | my $ret; | |
@@ -216,6 +304,20 sub is_member { | |||||
216 | $sth->finish(); |
|
304 | $sth->finish(); | |
217 | $dbh->disconnect(); |
|
305 | $dbh->disconnect(); | |
218 |
|
306 | |||
|
307 | if ($cfg->{RedmineCacheCredsMax} and $ret) { | |||
|
308 | if (defined $usrprojpass) { | |||
|
309 | $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest); | |||
|
310 | } else { | |||
|
311 | if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) { | |||
|
312 | $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest); | |||
|
313 | $cfg->{RedmineCacheCredsCount}++; | |||
|
314 | } else { | |||
|
315 | $cfg->{RedmineCacheCreds}->clear(); | |||
|
316 | $cfg->{RedmineCacheCredsCount} = 0; | |||
|
317 | } | |||
|
318 | } | |||
|
319 | } | |||
|
320 | ||||
219 | $ret; |
|
321 | $ret; | |
220 | } |
|
322 | } | |
221 |
|
323 | |||
@@ -229,9 +331,9 sub get_project_identifier { | |||||
229 |
|
331 | |||
230 | sub connect_database { |
|
332 | sub connect_database { | |
231 | my $r = shift; |
|
333 | my $r = shift; | |
232 |
|
334 | |||
233 | my ($dsn, $db_user, $db_pass) = map { $r->dir_config($_) } qw/dsn db_user db_pass/; |
|
335 | my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); | |
234 |
return DBI->connect($ |
|
336 | return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass}); | |
235 | } |
|
337 | } | |
236 |
|
338 | |||
237 | 1; |
|
339 | 1; |
General Comments 0
You need to be logged in to leave comments.
Login now