Project

General

Profile

« Previous | Next » 

Revision 916

  • add Redmine.pm to authenticate with mod_perl
  • add a --test option in reposman.rb
  • change owner right to fit with apache write access to repositories
  • add a deprecated warning in reposman.pl

View differences:

trunk/extra/svn/Redmine.pm
1
package Apache::Authn::Redmine;
2

  
3
=head1 Apache::Authn::Redmine
4

  
5
Redmine - a mod_perl module to authenticate webdav subversion users
6
against redmine database
7

  
8
=head1 SYNOPSIS
9

  
10
This module allow anonymous users to browse public project and
11
registred users to browse and commit their project. authentication is
12
done on the redmine database.
13

  
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
16
svn server.
17

  
18
=head1 INSTALLATION
19

  
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
22
migrate.
23

  
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
26
work on allmost all databases).
27

  
28
On debian/ubuntu you must do :
29

  
30
  aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
31

  
32
=head1 CONFIGURATION
33

  
34
   ## if the module isn't in your perl path
35
   PerlRequire /usr/local/apache/Redmine.pm
36
   ## else
37
   # PerlModule Apache::Authn::Redmine
38
   <Location /svn>
39
     DAV svn
40
     SVNParentPath "/var/svn"
41

  
42
     AuthType Basic
43
     AuthName redmine
44
     Require valid-user
45

  
46
     PerlAccessHandler Apache::Authn::Redmine::access_handler
47
     PerlAuthenHandler Apache::Authn::Redmine::authen_handler
48
  
49
     ## for mysql
50
     PerlSetVar dsn DBI:mysql:database=databasename;host=my.db.server
51
     ## for postgres
52
     # PerlSetVar dsn DBI:Pg:dbname=databasename;host=my.db.server
53

  
54
     PerlSetVar db_user redmine
55
     PerlSetVar db_pass password
56
  </Location>
57

  
58
To be able to browse repository inside redmine, you must add something
59
like that :
60

  
61
   <Location /svn-private>
62
     DAV svn
63
     SVNParentPath "/var/svn"
64
     Order deny,allow
65
     Deny from all
66
     # only allow reading orders
67
     <Limit GET PROPFIND OPTIONS REPORT>
68
       Allow from redmine.server.ip
69
     </Limit>
70
   </Location>
71

  
72
and you will have to use this reposman.rb command line to create repository :
73

  
74
  reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
75

  
76
=head1 MIGRATION FROM OLDER RELEASES
77

  
78
If you use an older reposman.rb (r860 or before), you need to change
79
rights on repositories to allow the apache user to read and write
80
S<them :>
81

  
82
  sudo chown -R www-data /var/svn/*
83
  sudo chmod -R u+w /var/svn/*
84

  
85
And you need to upgrade at least reposman.rb (after r860).
86

  
87
=cut
88

  
89
use strict;
90

  
91
use DBI;
92
use Digest::SHA1;
93

  
94
use Apache2::Module;
95
use Apache2::Access;
96
use Apache2::ServerRec qw();
97
use Apache2::RequestRec qw();
98
use Apache2::RequestUtil qw();
99
use Apache2::Const qw(:common);
100
# use Apache2::Directive qw();
101

  
102
my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
103

  
104
sub access_handler {
105
  my $r = shift;
106

  
107
  unless ($r->some_auth_required) {
108
      $r->log_reason("No authentication has been configured");
109
      return FORBIDDEN;
110
  }
111

  
112
  my $method = $r->method;
113
  return OK unless 1 == $read_only_methods{$method};
114

  
115
  my $project_id = get_project_identifier($r);
116

  
117
  $r->set_handlers(PerlAuthenHandler => [\&OK])
118
      if is_public_project($project_id, $r);
119

  
120
  return OK
121
}
122

  
123
sub authen_handler {
124
  my $r = shift;
125
  
126
  my ($res, $redmine_pass) =  $r->get_basic_auth_pw();
127
  return $res unless $res == OK;
128
  
129
  if (is_member($r->user, $redmine_pass, $r)) {
130
      return OK;
131
  } else {
132
      $r->note_auth_failure();
133
      return AUTH_REQUIRED;
134
  }
135
}
136

  
137
sub is_public_project {
138
    my $project_id = shift;
139
    my $r = shift;
140

  
141
    my $dbh = connect_database($r);
142
    my $sth = $dbh->prepare(
143
	"SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
144
    );
145

  
146
    $sth->execute($project_id);
147
    my $ret = $sth->fetchrow_array ? 1 : 0;
148
    $dbh->disconnect();
149

  
150
    $ret;
151
}
152

  
153
# perhaps we should use repository right (other read right) to check public access.
154
# it could be faster BUT it doesn't work for the moment.
155
# sub is_public_project_by_file {
156
#     my $project_id = shift;
157
#     my $r = shift;
158

  
159
#     my $tree = Apache2::Directive::conftree();
160
#     my $node = $tree->lookup('Location', $r->location);
161
#     my $hash = $node->as_hash;
162

  
163
#     my $svnparentpath = $hash->{SVNParentPath};
164
#     my $repos_path = $svnparentpath . "/" . $project_id;
165
#     return 1 if (stat($repos_path))[2] & 00007;
166
# }
167

  
168
sub is_member {
169
  my $redmine_user = shift;
170
  my $redmine_pass = shift;
171
  my $r = shift;
172

  
173
  my $dbh         = connect_database($r);
174
  my $project_id  = get_project_identifier($r);
175

  
176
  my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
177

  
178
  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 login=? AND identifier=?;"
180
  );
181
  $sth->execute($redmine_user, $project_id);
182

  
183
  my $ret;
184
  while (my @row = $sth->fetchrow_array) {
185
      if ($row[0] eq $pass_digest) {
186
	  $ret = 1;
187
	  last;
188
      }
189
  }
190
  $dbh->disconnect();
191

  
192
  $ret;
193
}
194

  
195
sub get_project_identifier {
196
    my $r = shift;
197
    
198
    my $location = $r->location;
199
    my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
200
    $identifier;
201
}
202

  
203
sub connect_database {
204
    my $r = shift;
205

  
206
    my ($dsn, $db_user, $db_pass) = map { $r->dir_config($_) } qw/dsn db_user db_pass/;
207
    return DBI->connect($dsn, $db_user, $db_pass);
208
}
209

  
210
1;
trunk/extra/svn/reposman.pl
23 23

  
24 24
$VERSION = "1.0";
25 25

  
26
my $warning = "This program is now deprecated. Use the reposman.rb for new features";
27
print STDERR "*" x length($warning), "\n",
28
    $warning, "\n",
29
    "*" x length($warning), "\n\n";
30

  
26 31
my %opts = (verbose => 0);
27 32
GetOptions(\%opts, 'verbose|v+', 'version|V', 'help|h', 'man|m', 'quiet|q', 'svn-dir|s=s', 'redmine-host|r=s') or pod2usage(2);
28 33

  
trunk/extra/svn/reposman.rb
37 37
#    -u file:///var/svn/                       # if the repository is local
38 38
#    if this option isn't set, reposman won't register the repository
39 39
#
40
# -t, --test
41
#    only show what should be done
40 42
#
41 43
# -h, --help:
42 44
#    show help and exit
......
64 66
                      ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
65 67
                      ['--owner',        '-o', GetoptLong::REQUIRED_ARGUMENT],
66 68
                      ['--url',          '-u', GetoptLong::REQUIRED_ARGUMENT],
69
                      ['--test',         '-t', GetoptLong::NO_ARGUMENT],
67 70
                      ['--verbose',      '-v', GetoptLong::NO_ARGUMENT],
68 71
                      ['--version',      '-V', GetoptLong::NO_ARGUMENT],
69 72
                      ['--help'   ,      '-h', GetoptLong::NO_ARGUMENT],
......
76 79
$repos_base   = ''
77 80
$svn_owner    = 'root'
78 81
$svn_url      = false
82
$test         = false
79 83

  
80 84
def log(text,level=0, exit=false)
81 85
  return if $quiet or level > $verbose
......
91 95
    when '--owner';          $svn_owner    = arg.dup
92 96
    when '--url';            $svn_url      = arg.dup
93 97
    when '--verbose';        $verbose += 1
98
    when '--test';           $test = true
94 99
    when '--version';        puts Version; exit
95 100
    when '--help';           RDoc::usage
96 101
    when '--quiet';          $quiet = true
......
100 105
  exit 1
101 106
end
102 107

  
108
if $test
109
  log("running in test mode")
110
end
111

  
103 112
$svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
104 113

  
105 114
if ($redmine_host.empty? or $repos_base.empty?)
......
136 145
    yield if block_given?
137 146
  else
138 147
    uid, gid = Etc.getpwnam($svn_owner).uid, Etc.getgrnam(project.identifier).gid
139
    right = project.is_public ? 0575 : 0570
148
    right = project.is_public ? 0775 : 0770
140 149
    yield if block_given?
141 150
    Find.find(repos_path) do |f|
142 151
      File.chmod right, f
......
176 185
    owner      = owner_name(repos_path)
177 186
    next if project.is_public == other_read and owner == $svn_owner
178 187

  
188
    if $test
189
      log("\tchange mode on #{repos_path}")
190
      next
191
    end
192

  
179 193
    begin
180 194
      set_owner_and_rights(project, repos_path)
181 195
    rescue Errno::EPERM => e
......
186 200
    log("\tmode change on #{repos_path}");
187 201

  
188 202
  else
189
    project.is_public ? File.umask(0202) : File.umask(0207)
203
    project.is_public ? File.umask(0002) : File.umask(0007)
190 204

  
205
    if $test
206
      log("\tcreate repository #{repos_path}")
207
      log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}") if $svn_url;
208
      next
209
    end
210

  
191 211
    begin
192 212
      set_owner_and_rights(project, repos_path) do
193 213
        raise "svnadmin create #{repos_path} failed" unless system("svnadmin", "create", repos_path)

Also available in: Unified diff