redMineのユーザでsvnリポジトリを認証する

http://d.hatena.ne.jp/rucifer_hacker/20070803/1186105118 みたいな感じの話。私の場合は、svnリポジトリredMineのプロジェクトを連動させて、redMineのプロジェクトメンバー以外は書き込みできない、とかしたかった。

そこで、mod_perlのモジュールを書いてみた。Perl書いたのは、6年ぶりくらいだぜ。http://redmine.soutaro.com/projects/show/2とかにおいてありますが、redmine.soutaro.comは、まだまだ気分で止めると思うので、こっちにもこぴぺしておきます。

package Apache::Authn::redMine;
# file: Apache/Authn/redMine.pm

use strict;

use DBI;
use Digest::SHA1;

use Apache2::Module;
use Apache2::Access;
use Apache2::ServerRec qw();
use Apache2::RequestRec qw();
use Apache2::RequestUtil qw();
use Apache2::Const qw(:common);

sub handler {
  my $r = shift;
  my $id = $r->dir_config('identity');
  
  my ($res, $redmine_pass) =  $r->get_basic_auth_pw();
  return $res if $res != Apache2::Const::OK;
  
  my $dsn = $r->dir_config("dsn");
  my $user = $r->dir_config("db_user");
  my $pass = $r->dir_config("db_pass");

  my $redmine_user = $r->user();

  if (try_redmine($dsn, $user, $pass, $id, $redmine_user, $redmine_pass)) {
    return Apache2::Const::OK;
  } else {
    $r->note_auth_failure();
    return Apache2::Const::AUTH_REQUIRED;
  }
}

sub try_redmine {
  my $dsn = shift;
  my $db_user = shift;
  my $db_pass = shift;
  my $redmine_id = shift;
  my $redmine_user = shift;
  my $redmine_pass = shift;

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

  my $dbh = DBI->connect($dsn, $db_user, $db_pass);
  my $sth = $dbh->prepare(
    "SELECT hashed_password FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND login=? AND identifier=?;"
  );

  $sth->execute($redmine_user, $redmine_id);

  while (my @row = $sth->fetchrow_array) {
    if ($row[0] eq $pass_digest) {
      return 1;
    }
  }

  $dbh->disconnect();

  return 0;
}

1;

使い方は、どっか適当なところに保存して、

# Add @INC to path this library is located in.
# or install to your system.
PerlSwitches -I[どっか適当なところ]

<Location [/authnredmine] >
  DAV svn
  SVNPath [/var/svn/authnredmine]

  AuthType Basic
  AuthName ["authnredmine respotiroy"]

  # Select authentication handler
  PerlAuthenHandler Apache::Authn::redMine

  # Setup some variables
  PerlSetVar identity [authnredmine]
  PerlSetVar dsn [DBI:mysql:redmine:localhost:3306]
  PerlSetVar db_user [redmine]
  PerlSetVar db_pass [password]
  
  Require valid-user

</Location>

みたいに書いてあげればいけるとおもう。

本当は、ユーザーのroleも見ないとダメだけど、そこまでやってられないので省略。あと、なんかの拍子にredMineのDB構造が変わると、アウトです。まあ、redMineはしばらく使ってみようと思うので、当面は面倒見ると思いますが。

LDAP使えばできるかもとか、mod_auth_dbdでいけないかとか、mod_auth_externalとか、考えたんですが、めんどくさくなりました。もっと適切な方法があったら教えてください。