##// END OF EJS Templates
Remove default Memcached namespace....
Liwiusz Ociepa -
r1631:f6b5632fec94
parent child
Show More
@@ -1,374 +1,368
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 ## Configuration for memcached
63 ## Configuration for memcached
64 # RedmineMemcacheServers "127.0.0.1:112211"
64 # RedmineMemcacheServers "127.0.0.1:112211"
65 # RedmineMemcacheExpirySec "12"
65 # RedmineMemcacheExpirySec "60"
66 # # Defaults to "RedminePM:"
67 # RedmineMemcacheNamespace "RedmineCreds:"
66 # RedmineMemcacheNamespace "RedmineCreds:"
68 </Location>
67 </Location>
69
68
70 To be able to browse repository inside redmine, you must add something
69 To be able to browse repository inside redmine, you must add something
71 like that :
70 like that :
72
71
73 <Location /svn-private>
72 <Location /svn-private>
74 DAV svn
73 DAV svn
75 SVNParentPath "/var/svn"
74 SVNParentPath "/var/svn"
76 Order deny,allow
75 Order deny,allow
77 Deny from all
76 Deny from all
78 # only allow reading orders
77 # only allow reading orders
79 <Limit GET PROPFIND OPTIONS REPORT>
78 <Limit GET PROPFIND OPTIONS REPORT>
80 Allow from redmine.server.ip
79 Allow from redmine.server.ip
81 </Limit>
80 </Limit>
82 </Location>
81 </Location>
83
82
84 and you will have to use this reposman.rb command line to create repository :
83 and you will have to use this reposman.rb command line to create repository :
85
84
86 reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
85 reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
87
86
88 =head1 MIGRATION FROM OLDER RELEASES
87 =head1 MIGRATION FROM OLDER RELEASES
89
88
90 If you use an older reposman.rb (r860 or before), you need to change
89 If you use an older reposman.rb (r860 or before), you need to change
91 rights on repositories to allow the apache user to read and write
90 rights on repositories to allow the apache user to read and write
92 S<them :>
91 S<them :>
93
92
94 sudo chown -R www-data /var/svn/*
93 sudo chown -R www-data /var/svn/*
95 sudo chmod -R u+w /var/svn/*
94 sudo chmod -R u+w /var/svn/*
96
95
97 And you need to upgrade at least reposman.rb (after r860).
96 And you need to upgrade at least reposman.rb (after r860).
98
97
99 =cut
98 =cut
100
99
101 use strict;
100 use strict;
102 use warnings FATAL => 'all', NONFATAL => 'redefine';
101 use warnings FATAL => 'all', NONFATAL => 'redefine';
103
102
104 use DBI;
103 use DBI;
105 use Digest::SHA1;
104 use Digest::SHA1;
106 # optional module for LDAP authentication
105 # optional module for LDAP authentication
107 my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
106 my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
108 my $CanUseMemcached = eval("use Cache::Memcached; 1");
107 my $CanUseMemcached = eval("use Cache::Memcached; 1");
109
108
110 use Apache2::Module;
109 use Apache2::Module;
111 use Apache2::Access;
110 use Apache2::Access;
112 use Apache2::ServerRec qw();
111 use Apache2::ServerRec qw();
113 use Apache2::RequestRec qw();
112 use Apache2::RequestRec qw();
114 use Apache2::RequestUtil qw();
113 use Apache2::RequestUtil qw();
115 use Apache2::Const qw(:common :override :cmd_how);
114 use Apache2::Const qw(:common :override :cmd_how);
116
115
117 # use Apache2::Directive qw();
116 # use Apache2::Directive qw();
118
117
119 my @directives = (
118 my @directives = (
120 {
119 {
121 name => 'RedmineDSN',
120 name => 'RedmineDSN',
122 req_override => OR_AUTHCFG,
121 req_override => OR_AUTHCFG,
123 args_how => TAKE1,
122 args_how => TAKE1,
124 errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
123 errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
125 },
124 },
126 {
125 {
127 name => 'RedmineDbUser',
126 name => 'RedmineDbUser',
128 req_override => OR_AUTHCFG,
127 req_override => OR_AUTHCFG,
129 args_how => TAKE1,
128 args_how => TAKE1,
130 },
129 },
131 {
130 {
132 name => 'RedmineDbPass',
131 name => 'RedmineDbPass',
133 req_override => OR_AUTHCFG,
132 req_override => OR_AUTHCFG,
134 args_how => TAKE1,
133 args_how => TAKE1,
135 },
134 },
136 {
135 {
137 name => 'RedmineDbWhereClause',
136 name => 'RedmineDbWhereClause',
138 req_override => OR_AUTHCFG,
137 req_override => OR_AUTHCFG,
139 args_how => TAKE1,
138 args_how => TAKE1,
140 },
139 },
141 {
140 {
142 name => 'RedmineMemcacheServers',
141 name => 'RedmineMemcacheServers',
143 req_override => OR_AUTHCFG,
142 req_override => OR_AUTHCFG,
144 args_how => TAKE1,
143 args_how => TAKE1,
145 },
144 },
146 {
145 {
147 name => 'RedmineMemcacheExpirySec',
146 name => 'RedmineMemcacheExpirySec',
148 req_override => OR_AUTHCFG,
147 req_override => OR_AUTHCFG,
149 args_how => TAKE1,
148 args_how => TAKE1,
150 },
149 },
151 {
150 {
152 name => 'RedmineMemcacheNamespace',
151 name => 'RedmineMemcacheNamespace',
153 req_override => OR_AUTHCFG,
152 req_override => OR_AUTHCFG,
154 args_how => TAKE1,
153 args_how => TAKE1,
155 },
154 },
156 );
155 );
157
156
158 sub RedmineDSN {
157 sub RedmineDSN {
159 my ($self, $parms, $arg) = @_;
158 my ($self, $parms, $arg) = @_;
160 $self->{RedmineDSN} = $arg;
159 $self->{RedmineDSN} = $arg;
161 my $query = "SELECT
160 my $query = "SELECT
162 hashed_password, auth_source_id
161 hashed_password, auth_source_id
163 FROM members, projects, users
162 FROM members, projects, users
164 WHERE
163 WHERE
165 projects.id=members.project_id
164 projects.id=members.project_id
166 AND users.id=members.user_id
165 AND users.id=members.user_id
167 AND users.status=1
166 AND users.status=1
168 AND login=?
167 AND login=?
169 AND identifier=? ";
168 AND identifier=? ";
170 $self->{RedmineQuery} = trim($query);
169 $self->{RedmineQuery} = trim($query);
171 }
170 }
172 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
171 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
173 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
172 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
174 sub RedmineDbWhereClause {
173 sub RedmineDbWhereClause {
175 my ($self, $parms, $arg) = @_;
174 my ($self, $parms, $arg) = @_;
176 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
175 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
177 }
176 }
178
177
179 sub RedmineMemcacheServers {
178 sub RedmineMemcacheServers {
180 my ($self, $parms, $arg) = @_;
179 my ($self, $parms, $arg) = @_;
181 if ($arg && $CanUseMemcached) {
180 if ($arg && $CanUseMemcached) {
182 $self->{RedmineMemcached} = new Cache::Memcached {
181 $self->{RedmineMemcached} = new Cache::Memcached {
183 'servers' => [ $arg, ],
182 'servers' => [ $arg, ],
184 'debug' => 1,
183 'debug' => 1,
185 };
184 };
186 $self->{RedmineMemcache} = 1;
185 $self->{RedmineMemcache} = 1;
187 # Undocumented feature of Cache::Memcached, please don't kill me
188 if (0 == length $self->{RedmineMemcached}->{namespace}) {
189 $self->{RedmineMemcached}->{namespace} = "RedminePM:";
190 $self->{RedmineMemcached}->{namespace_len} = length $self->{RedmineMemcached}->{namespace};
191 }
192 }
186 }
193 }
187 }
194
188
195 sub RedmineMemcacheExpirySec { set_val('RedmineMemcacheExpirySec', @_); }
189 sub RedmineMemcacheExpirySec { set_val('RedmineMemcacheExpirySec', @_); }
196
190
197 sub RedmineMemcacheNamespace {
191 sub RedmineMemcacheNamespace {
198 my ($self, $parms, $arg) = @_;
192 my ($self, $parms, $arg) = @_;
199 if ($CanUseMemcached) {
193 if ($CanUseMemcached) {
200 # Undocumented feature of Cache::Memcached, please don't kill me
194 # Undocumented feature of Cache::Memcached, please don't kill me
201 $self->{RedmineMemcached}->{namespace} = $arg;
195 $self->{RedmineMemcached}->{namespace} = $arg;
202 $self->{RedmineMemcached}->{namespace_len} = length $self->{RedmineMemcached}->{namespace};
196 $self->{RedmineMemcached}->{namespace_len} = length $self->{RedmineMemcached}->{namespace};
203 }
197 }
204 }
198 }
205
199
206 sub trim {
200 sub trim {
207 my $string = shift;
201 my $string = shift;
208 $string =~ s/\s{2,}/ /g;
202 $string =~ s/\s{2,}/ /g;
209 return $string;
203 return $string;
210 }
204 }
211
205
212 sub set_val {
206 sub set_val {
213 my ($key, $self, $parms, $arg) = @_;
207 my ($key, $self, $parms, $arg) = @_;
214 $self->{$key} = $arg;
208 $self->{$key} = $arg;
215 }
209 }
216
210
217 Apache2::Module::add(__PACKAGE__, \@directives);
211 Apache2::Module::add(__PACKAGE__, \@directives);
218
212
219
213
220 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
214 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
221
215
222 sub access_handler {
216 sub access_handler {
223 my $r = shift;
217 my $r = shift;
224
218
225 unless ($r->some_auth_required) {
219 unless ($r->some_auth_required) {
226 $r->log_reason("No authentication has been configured");
220 $r->log_reason("No authentication has been configured");
227 return FORBIDDEN;
221 return FORBIDDEN;
228 }
222 }
229
223
230 my $method = $r->method;
224 my $method = $r->method;
231 return OK if defined $read_only_methods{$method};
225 return OK if defined $read_only_methods{$method};
232
226
233 my $project_id = get_project_identifier($r);
227 my $project_id = get_project_identifier($r);
234
228
235 $r->set_handlers(PerlAuthenHandler => [\&OK])
229 $r->set_handlers(PerlAuthenHandler => [\&OK])
236 if is_public_project($project_id, $r);
230 if is_public_project($project_id, $r);
237
231
238 return OK
232 return OK
239 }
233 }
240
234
241 sub authen_handler {
235 sub authen_handler {
242 my $r = shift;
236 my $r = shift;
243
237
244 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
238 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
245 return $res unless $res == OK;
239 return $res unless $res == OK;
246
240
247 if (is_member($r->user, $redmine_pass, $r)) {
241 if (is_member($r->user, $redmine_pass, $r)) {
248 return OK;
242 return OK;
249 } else {
243 } else {
250 $r->note_auth_failure();
244 $r->note_auth_failure();
251 return AUTH_REQUIRED;
245 return AUTH_REQUIRED;
252 }
246 }
253 }
247 }
254
248
255 sub is_public_project {
249 sub is_public_project {
256 my $project_id = shift;
250 my $project_id = shift;
257 my $r = shift;
251 my $r = shift;
258
252
259 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
253 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
260 if ($cfg->{RedmineMemcache}) {
254 if ($cfg->{RedmineMemcache}) {
261 return 1 if ($cfg->{RedmineMemcached}->get($project_id));
255 return 1 if ($cfg->{RedmineMemcached}->get($project_id));
262 }
256 }
263 my $dbh = connect_database($r);
257 my $dbh = connect_database($r);
264 my $sth = $dbh->prepare(
258 my $sth = $dbh->prepare(
265 "SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
259 "SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
266 );
260 );
267
261
268 $sth->execute($project_id);
262 $sth->execute($project_id);
269 my $ret = $sth->fetchrow_array ? 1 : 0;
263 my $ret = $sth->fetchrow_array ? 1 : 0;
270 $sth->finish();
264 $sth->finish();
271 $dbh->disconnect();
265 $dbh->disconnect();
272 if ($cfg->{RedmineMemcache}) {
266 if ($cfg->{RedmineMemcache}) {
273 if ($cfg->{RedmineMemcacheExpirySec}) {
267 if ($cfg->{RedmineMemcacheExpirySec}) {
274 $cfg->{RedmineMemcached}->set($project_id, $ret, $cfg->{RedmineMemcacheExpirySec});
268 $cfg->{RedmineMemcached}->set($project_id, $ret, $cfg->{RedmineMemcacheExpirySec});
275 } else {
269 } else {
276 $cfg->{RedmineMemcached}->set($project_id, $ret);
270 $cfg->{RedmineMemcached}->set($project_id, $ret);
277 }
271 }
278 }
272 }
279
273
280
274
281 $ret;
275 $ret;
282 }
276 }
283
277
284 # perhaps we should use repository right (other read right) to check public access.
278 # perhaps we should use repository right (other read right) to check public access.
285 # it could be faster BUT it doesn't work for the moment.
279 # it could be faster BUT it doesn't work for the moment.
286 # sub is_public_project_by_file {
280 # sub is_public_project_by_file {
287 # my $project_id = shift;
281 # my $project_id = shift;
288 # my $r = shift;
282 # my $r = shift;
289
283
290 # my $tree = Apache2::Directive::conftree();
284 # my $tree = Apache2::Directive::conftree();
291 # my $node = $tree->lookup('Location', $r->location);
285 # my $node = $tree->lookup('Location', $r->location);
292 # my $hash = $node->as_hash;
286 # my $hash = $node->as_hash;
293
287
294 # my $svnparentpath = $hash->{SVNParentPath};
288 # my $svnparentpath = $hash->{SVNParentPath};
295 # my $repos_path = $svnparentpath . "/" . $project_id;
289 # my $repos_path = $svnparentpath . "/" . $project_id;
296 # return 1 if (stat($repos_path))[2] & 00007;
290 # return 1 if (stat($repos_path))[2] & 00007;
297 # }
291 # }
298
292
299 sub is_member {
293 sub is_member {
300 my $redmine_user = shift;
294 my $redmine_user = shift;
301 my $redmine_pass = shift;
295 my $redmine_pass = shift;
302 my $r = shift;
296 my $r = shift;
303
297
304 my $dbh = connect_database($r);
298 my $dbh = connect_database($r);
305 my $project_id = get_project_identifier($r);
299 my $project_id = get_project_identifier($r);
306
300
307 my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
301 my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
308
302
309 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
303 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
310 my $usrprojpass;
304 my $usrprojpass;
311 if ($cfg->{RedmineMemcache}) {
305 if ($cfg->{RedmineMemcache}) {
312 $usrprojpass = $cfg->{RedmineMemcached}->get($redmine_user.":".$project_id);
306 $usrprojpass = $cfg->{RedmineMemcached}->get($redmine_user.":".$project_id);
313 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
307 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
314 }
308 }
315 my $query = $cfg->{RedmineQuery};
309 my $query = $cfg->{RedmineQuery};
316 my $sth = $dbh->prepare($query);
310 my $sth = $dbh->prepare($query);
317 $sth->execute($redmine_user, $project_id);
311 $sth->execute($redmine_user, $project_id);
318
312
319 my $ret;
313 my $ret;
320 while (my @row = $sth->fetchrow_array) {
314 while (my @row = $sth->fetchrow_array) {
321 unless ($row[1]) {
315 unless ($row[1]) {
322 if ($row[0] eq $pass_digest) {
316 if ($row[0] eq $pass_digest) {
323 $ret = 1;
317 $ret = 1;
324 last;
318 last;
325 }
319 }
326 } elsif ($CanUseLDAPAuth) {
320 } elsif ($CanUseLDAPAuth) {
327 my $sthldap = $dbh->prepare(
321 my $sthldap = $dbh->prepare(
328 "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
322 "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
329 );
323 );
330 $sthldap->execute($row[1]);
324 $sthldap->execute($row[1]);
331 while (my @rowldap = $sthldap->fetchrow_array) {
325 while (my @rowldap = $sthldap->fetchrow_array) {
332 my $ldap = Authen::Simple::LDAP->new(
326 my $ldap = Authen::Simple::LDAP->new(
333 host => ($rowldap[2] == 1 || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]" : $rowldap[0],
327 host => ($rowldap[2] == 1 || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]" : $rowldap[0],
334 port => $rowldap[1],
328 port => $rowldap[1],
335 basedn => $rowldap[5],
329 basedn => $rowldap[5],
336 binddn => $rowldap[3] ? $rowldap[3] : "",
330 binddn => $rowldap[3] ? $rowldap[3] : "",
337 bindpw => $rowldap[4] ? $rowldap[4] : "",
331 bindpw => $rowldap[4] ? $rowldap[4] : "",
338 filter => "(".$rowldap[6]."=%s)"
332 filter => "(".$rowldap[6]."=%s)"
339 );
333 );
340 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass));
334 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass));
341 }
335 }
342 $sthldap->finish();
336 $sthldap->finish();
343 }
337 }
344 }
338 }
345 $sth->finish();
339 $sth->finish();
346 $dbh->disconnect();
340 $dbh->disconnect();
347
341
348 if ($cfg->{RedmineMemcache} and $ret) {
342 if ($cfg->{RedmineMemcache} and $ret) {
349 if ($cfg->{RedmineMemcacheExpirySec}) {
343 if ($cfg->{RedmineMemcacheExpirySec}) {
350 $cfg->{RedmineMemcached}->set($redmine_user.":".$project_id, $pass_digest, $cfg->{RedmineMemcacheExpirySec});
344 $cfg->{RedmineMemcached}->set($redmine_user.":".$project_id, $pass_digest, $cfg->{RedmineMemcacheExpirySec});
351 } else {
345 } else {
352 $cfg->{RedmineMemcached}->set($redmine_user.":".$project_id, $pass_digest);
346 $cfg->{RedmineMemcached}->set($redmine_user.":".$project_id, $pass_digest);
353 }
347 }
354 }
348 }
355
349
356 $ret;
350 $ret;
357 }
351 }
358
352
359 sub get_project_identifier {
353 sub get_project_identifier {
360 my $r = shift;
354 my $r = shift;
361
355
362 my $location = $r->location;
356 my $location = $r->location;
363 my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
357 my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
364 $identifier;
358 $identifier;
365 }
359 }
366
360
367 sub connect_database {
361 sub connect_database {
368 my $r = shift;
362 my $r = shift;
369
363
370 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
364 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
371 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
365 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
372 }
366 }
373
367
374 1;
368 1;
General Comments 0
You need to be logged in to leave comments. Login now