##// END OF EJS Templates
Redmine.pm support for LDAP authentication (patch by Liwiusz Ociepa). Closes #879, #918....
Jean-Philippe Lang -
r1320:246e8f67c598
parent child
Show More
@@ -1,210 +1,231
1 1 package Apache::Authn::Redmine;
2 2
3 3 =head1 Apache::Authn::Redmine
4 4
5 5 Redmine - a mod_perl module to authenticate webdav subversion users
6 6 against redmine database
7 7
8 8 =head1 SYNOPSIS
9 9
10 10 This module allow anonymous users to browse public project and
11 11 registred users to browse and commit their project. authentication is
12 12 done on the redmine database.
13 13
14 14 This method is far simpler than the one with pam_* and works with all
15 15 database without an hassle but you need to have apache/mod_perl on the
16 16 svn server.
17 17
18 18 =head1 INSTALLATION
19 19
20 20 For this to automagically work, you need to have a recent reposman.rb
21 21 (after r860) and if you already use reposman, read the last section to
22 22 migrate.
23 23
24 24 Sorry ruby users but you need some perl modules, at least mod_perl2,
25 25 DBI and DBD::mysql (or the DBD driver for you database as it should
26 26 work on allmost all databases).
27 27
28 28 On debian/ubuntu you must do :
29 29
30 30 aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
31 31
32 32 =head1 CONFIGURATION
33 33
34 34 ## if the module isn't in your perl path
35 35 PerlRequire /usr/local/apache/Redmine.pm
36 36 ## else
37 37 # PerlModule Apache::Authn::Redmine
38 38 <Location /svn>
39 39 DAV svn
40 40 SVNParentPath "/var/svn"
41 41
42 42 AuthType Basic
43 43 AuthName redmine
44 44 Require valid-user
45 45
46 46 PerlAccessHandler Apache::Authn::Redmine::access_handler
47 47 PerlAuthenHandler Apache::Authn::Redmine::authen_handler
48 48
49 49 ## for mysql
50 50 PerlSetVar dsn DBI:mysql:database=databasename;host=my.db.server
51 51 ## for postgres
52 52 # PerlSetVar dsn DBI:Pg:dbname=databasename;host=my.db.server
53 53
54 54 PerlSetVar db_user redmine
55 55 PerlSetVar db_pass password
56 56 </Location>
57 57
58 58 To be able to browse repository inside redmine, you must add something
59 59 like that :
60 60
61 61 <Location /svn-private>
62 62 DAV svn
63 63 SVNParentPath "/var/svn"
64 64 Order deny,allow
65 65 Deny from all
66 66 # only allow reading orders
67 67 <Limit GET PROPFIND OPTIONS REPORT>
68 68 Allow from redmine.server.ip
69 69 </Limit>
70 70 </Location>
71 71
72 72 and you will have to use this reposman.rb command line to create repository :
73 73
74 74 reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
75 75
76 76 =head1 MIGRATION FROM OLDER RELEASES
77 77
78 78 If you use an older reposman.rb (r860 or before), you need to change
79 79 rights on repositories to allow the apache user to read and write
80 80 S<them :>
81 81
82 82 sudo chown -R www-data /var/svn/*
83 83 sudo chmod -R u+w /var/svn/*
84 84
85 85 And you need to upgrade at least reposman.rb (after r860).
86 86
87 87 =cut
88 88
89 89 use strict;
90 90
91 91 use DBI;
92 92 use Digest::SHA1;
93 use Authen::Simple::LDAP;
93 94
94 95 use Apache2::Module;
95 96 use Apache2::Access;
96 97 use Apache2::ServerRec qw();
97 98 use Apache2::RequestRec qw();
98 99 use Apache2::RequestUtil qw();
99 100 use Apache2::Const qw(:common);
100 101 # use Apache2::Directive qw();
101 102
102 103 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
103 104
104 105 sub access_handler {
105 106 my $r = shift;
106 107
107 108 unless ($r->some_auth_required) {
108 109 $r->log_reason("No authentication has been configured");
109 110 return FORBIDDEN;
110 111 }
111 112
112 113 my $method = $r->method;
113 114 return OK unless 1 == $read_only_methods{$method};
114 115
115 116 my $project_id = get_project_identifier($r);
116 117
117 118 $r->set_handlers(PerlAuthenHandler => [\&OK])
118 119 if is_public_project($project_id, $r);
119 120
120 121 return OK
121 122 }
122 123
123 124 sub authen_handler {
124 125 my $r = shift;
125 126
126 127 my ($res, $redmine_pass) = $r->get_basic_auth_pw();
127 128 return $res unless $res == OK;
128 129
129 130 if (is_member($r->user, $redmine_pass, $r)) {
130 131 return OK;
131 132 } else {
132 133 $r->note_auth_failure();
133 134 return AUTH_REQUIRED;
134 135 }
135 136 }
136 137
137 138 sub is_public_project {
138 139 my $project_id = shift;
139 140 my $r = shift;
140 141
141 142 my $dbh = connect_database($r);
142 143 my $sth = $dbh->prepare(
143 "SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
144 "SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
144 145 );
145 146
146 147 $sth->execute($project_id);
147 148 my $ret = $sth->fetchrow_array ? 1 : 0;
148 149 $dbh->disconnect();
149 150
150 151 $ret;
151 152 }
152 153
153 154 # perhaps we should use repository right (other read right) to check public access.
154 155 # it could be faster BUT it doesn't work for the moment.
155 156 # sub is_public_project_by_file {
156 157 # my $project_id = shift;
157 158 # my $r = shift;
158 159
159 160 # my $tree = Apache2::Directive::conftree();
160 161 # my $node = $tree->lookup('Location', $r->location);
161 162 # my $hash = $node->as_hash;
162 163
163 164 # my $svnparentpath = $hash->{SVNParentPath};
164 165 # my $repos_path = $svnparentpath . "/" . $project_id;
165 166 # return 1 if (stat($repos_path))[2] & 00007;
166 167 # }
167 168
168 169 sub is_member {
169 170 my $redmine_user = shift;
170 171 my $redmine_pass = shift;
171 172 my $r = shift;
172 173
173 174 my $dbh = connect_database($r);
174 175 my $project_id = get_project_identifier($r);
175 176
176 177 my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
177 178
178 179 my $sth = $dbh->prepare(
179 "SELECT hashed_password FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND users.status=1 AND login=? AND identifier=?;"
180 "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=?;"
180 181 );
181 182 $sth->execute($redmine_user, $project_id);
182 183
183 184 my $ret;
184 185 while (my @row = $sth->fetchrow_array) {
185 if ($row[0] eq $pass_digest) {
186 $ret = 1;
187 last;
186 unless ($row[1]) {
187 if ($row[0] eq $pass_digest) {
188 $ret = 1;
189 last;
190 }
191 } else {
192 my $sthldap = $dbh->prepare(
193 "SELECT host,port,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
194 );
195 $sthldap->execute($row[1]);
196 while (my @rowldap = $sthldap->fetchrow_array) {
197 my $ldap = Authen::Simple::LDAP->new(
198 host => $rowldap[0],
199 port => $rowldap[1],
200 basedn => $rowldap[4],
201 binddn => $rowldap[2] ? $rowldap[2] : "",
202 bindpw => $rowldap[3] ? $rowldap[3] : "",
203 filter => "(".$rowldap[5]."=%s)"
204 );
205 $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass));
206 }
207 $sthldap->finish();
188 208 }
189 209 }
210 $sth->finish();
190 211 $dbh->disconnect();
191 212
192 213 $ret;
193 214 }
194 215
195 216 sub get_project_identifier {
196 217 my $r = shift;
197 218
198 219 my $location = $r->location;
199 220 my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
200 221 $identifier;
201 222 }
202 223
203 224 sub connect_database {
204 225 my $r = shift;
205 226
206 227 my ($dsn, $db_user, $db_pass) = map { $r->dir_config($_) } qw/dsn db_user db_pass/;
207 228 return DBI->connect($dsn, $db_user, $db_pass);
208 229 }
209 230
210 231 1;
General Comments 0
You need to be logged in to leave comments. Login now