miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました

mod_authz_svn を使おうとして挫折したりとか

最近プロジェクトの情報をなるべく(社内で)オープンにして、一部分のみセキュリティをかける方針に変更中です。

TracWiki については

に書きましたが、SVN でも似たような設定をやろうと思いまして。だったら mod_authz_svn 使いたいよねと思ったんだけどうまくいかなかったので、そのあたりのお話。

ちなみにただの作業記録なので、同じ問題にハマってる方以外には役にたたないと思います。

前提

Apache 上で mod_dav_svn が動いていて、

<Location /svn>
  DAV svn
  SVNParentPath /home/svn
</Location>

<Location /svn/proj1>
    # Limit write permission to list of valid users.
    AuthType Basic
    AuthName "Subversion Repository(proj1)"
    AuthUserFile /home/trac/proj1/trac.htpasswd
    <LimitExcept GET PROPFIND OPTIONS REPORT>
        Require valid-user
    </LimitExcept>
</Location>

こんな感じで SVNParentPath を使ったマルチリポジトリ構成。

以前はユーザ認証自体かかってなかったんだけど、それだとログにユーザ名が残らなかったりして不便なので、最近やってるプロジェクトではプロジェクトごとに passwd ファイルを用意して、Apache 側でも個別にそれを指定している形。で、リポジトリに編集操作をする場合はユーザ認証が必要になる、と。

やりたいこと

認証ユーザのみ読み書きが行え、anonymous は読み込みもできないような /proj1/protected みたいなディレクトリを作成したい。

設定してみる→失敗

mod_authz_svn はすでに有効になっているようなので、

あたりを参考に設定してみる。

httpd.conf は

<Location /svn/proj1>
    AuthzSVNAccessFile /home/svn/proj1/conf/authz

    Satisfy Any
    Require valid-user

    AuthType Basic
    AuthName "Subversion Repository(proj1)"
    AuthUserFile /home/trac/proj1/trac.htpasswd
</Location>

こうやって。authz は、

[groups]
developers = user1,user2,user3

[/]
@developers = rw
* = r

[/protected]
@developers = rw
* =

こう。

で、http://trac-server/svn/proj1/doc/http://trac-server/svn/proj1/protected/ をブラウザから開いてみると・・・anonymous でも普通に見れちゃってる。あれ?
そして http://trac-server/svn/proj1/ にアクセスしてみると・・・403 Forbidden。なにがなにやら。

Apache のエラーログには、/proj1 を開いたタイミングで

[error] The URI does not contain the name of a repository. [403, #190001]

みたいなログが残っている模様。

原因調査

ここで調査にいろいろてこずったんだけど、

  • httpd.conf の Require valid-user を削る
  • authz をすべてコメントアウトする(=すべてのユーザで読み書きできない)

状態で確認を取るのが手っ取り早い感じ。

この状態でログを確認すると、/proj1 は前のままだけど、/proj1/doc や /proj1/protected も 403 Forbidden になって、

[error] Access denied: - GET doc:/
[error] Access denied: - GET protected:/

というようなエラーログが吐かれることがわかった。なんでディレクトリの名前がリポジトリ名と認識されちゃってるの?

SVNPath を設定してみる→これも失敗

なんかわからないけど、SVNParentPath の設定が邪魔してるみたいなので、

<Location /svn/proj1>
    SVNPath /home/svn/proj1
    AuthzSVNAccessFile /home/svn/proj1/conf/authz

    Satisfy Any
    Require valid-user

    AuthType Basic
    AuthName "Subversion Repository(proj1)"
    AuthUserFile /home/trac/proj1/trac.htpasswd
</Location>

みたいにサブディレクトリ側で SVNPath を設定する形に変えてみる。(親ディレクトリの SVNParentPath 設定は残したまま。)

すると、/proj1/protected を開いたタイミングで 403 Forbidden になって、エラーログにも

[error] Access denied: - GET proj1:/protected

と表示される。プロジェクトとパスは正しく認識されているらしい。

でも /proj1 や /proj1/doc を開くと、500 Internal Server Error になってしまって、画面には

<?xml version="1.0" encoding="utf-8"?>
<D:error xmlns:D="DAV:" xmlns:m="http://apache.org/dav/xmlns" xmlns:C="svn:">
<C:error/>
<m:human-readable errcode="2">
Could not open the requested SVN filesystem
</m:human-readable>
</D:error>

こんなエラーが出る。そのときのエラーログは、

[error] (20014)Error string not specified yet: Can't open file '/home/svn/svn/format': No such file or directory
[error] Could not fetch resource information. [500, #0]
[error] Could not open the requested SVN filesystem [500, #2]
[error] Could not open the requested SVN filesystem [500, #2]

とかなんとか。パスが /svn/svn みたいになっちゃってるところを見ると、まだ SVNParentPath の設定が悪さしてるのかな。

サブディレクトリでも DAV svn を指定してみる→これまた失敗

ためしに、

<Location /svn/proj1>
    DAV svn
    SVNPath /home/svn/proj1
    AuthzSVNAccessFile /home/svn/proj1/conf/authz

    Satisfy Any
    Require valid-user

    AuthType Basic
    AuthName "Subversion Repository(proj1)"
    AuthUserFile /home/trac/proj1/trac.htpasswd
</Location>

こう(DAV svn の行を追加)してみた。すると、

  • /proj1、/proj1/doc は誰でも閲覧できる
  • /proj1/protected は認証後のみ閲覧できる

という期待どおりの動作になった。

・・・と思いきや。svn コマンドでこのリポジトリを利用しようとすると、

svn: コミットに失敗しました (詳しい理由は以下のとおりです):
svn: MKACTIVITY (URL: '/svn/proj1/proj1/!svn/act/b57dd0a8-bf76-0410-9c89-cdc855475c64'): 403 Forbidden (http://trac-server)

とかなんとかエラーになってしまった。proj1/proj1 とかいうパスが出現しているところを見ると、やっぱり SVNParentPath の設定がどこかで生きてて、変な不整合を起こしているらしい。

  • ためしに SVNParentPath の記述を消すとうまくいった
  • SVNListParentPath On にすると /proj1 でなぜか / 相当の情報(本来のプロジェクト一覧)が見えたりした

という感じ。

その他試したこと

あたりを見ながら Apache の設定をいじってみたけど、すべて失敗。

たとえば「/proj1/proj1/!svn になってるなら、!svn を ../!svn に変えればうまいこといくんじゃね?」と

SVNSpecialURI ../!svn

なんてこともやってみたけど、

Syntax error on line 1106 of /usr/local/apache2/conf/httpd.conf:
SVNSpecialURI not allowed here

こんなエラーになったりとか。まあうまくいっても怪しすぎて困るんだけど。

あきらめた

で、オプション見てて気づいたけど、SVNPath と SVNParentPath は両方指定してはいけないことになってるみたい。すべてのリポジトリで共通の authz を使って、ユーザの制御なんかもそちらでやれって話みたいですね。そうでなければ /svn2 みたいな Location を別途用意して、/svn は SVNParentPath で、/svn は SVNPath で運用するとか。

まあ今回はそこまで手を入れる気はないし、mod_authz_svn を使わずに Apache 側だけで設定しちゃえってことで。最終的にこうなりました。

<Location /svn/proj1>
    # Limit write permission to list of valid users.
    AuthType Basic
    AuthName "Subversion Repository(proj1)"
    AuthUserFile /home/trac/proj1/trac.htpasswd
    <LimitExcept GET PROPFIND OPTIONS REPORT>
        Require valid-user
    </LimitExcept>
</Location>

<Location /svn/proj1/protected>
    Require valid-user
</Location>

/proj1/protected 用に個別に設定を持つ形。今回は認証の有無だけで振り分ければいいのでこれでも問題なし。今後ルールが複雑になったら、passwd ファイルを増やしてパスごとに個別に設定する形になるのかな。

・・・とまあ今回は mod_authz_svn の使用はあきらめたんですが、SVNPatentPath 指定でもサブディレクトリ毎に authz を指定できるべきのような・・・。mod_dav_svn のバージョンは 1.3.2 とか結構古いので、もしかしたら最新版で直ってるかも。(一応 changelog は眺めたけど、それっぽいの無かった。)

結局調査に何時間もかけちゃったなぁ。これくらいの時間があれば、ソース読んで仕組みを把握できてたかも。