LoginSignup
0
3

More than 5 years have passed since last update.

ディレクトリ毎に別ユーザ名のBASIC認証をかけられるようにする(縛りアリ)

Posted at

色々出来ることに制限のある環境で以下のような要件を満たす httpd.conf の設定を編み出したメモ。

まず httpd-2.2 でほぼ静的な設定の既存WEBサーバ環境があった。で、そこの一部ディレクトリにBASIC認証をかけたいという依頼を受けた。しかし色々縛りがあって以外に大変だったわ…というネタ。

ちなみに結構変態に分類される設定だと思うが、単に縛りの中で頑張ったら出来ましたってだけの設定を吐き出してるだけなので、他の誰の参考にもならない気がする。.htaccess が使えるなら使えば良いし、httpd-2.2 以外にして良いとか、間に別のProxy挟んで良いとか、他のモジュール入れて良いとか、他の手段が選べるならもっと楽で真っ当な方法を検討したほうが良い。

要件

  • 要求
    • /secret/ 以下にBASIC認証をかけたい
    • /secret/foo と /secret/bar はそれぞれ別のID/PASSにしたい。
    • /secret/ 以下のディレクトリ名は不定(依頼者が新しく任意のディレクトリを作って、ID/PASSを発行する)
    • パスワードの発行管理は依頼者自身が行えるようにしたい。( /secret/.htpasswd の編集で完結させる)。
  • 制限事項
    • httpd のバージョンは 2.2 系(2.4ではない)
    • .htaccess は使わせられない(AllowOverride None
    • /secret/ 以下に新しいディレクトリを作る毎に面倒は見れない
    • 依頼者は新規ディレクトリの作成とパスワードファイルの編集のみ自由にできる。
  • やっかないなポイント
    • .htaccess は有効化出来ず、httpd.conf に初回に1度設定追加を行うことしか出来ない。
      • ないのでBASIC認証の設定が出来るのは /secret ディレクトリに対する1つだけ
    • require valid-user だけじゃ駄目なのは明らか(ディレクトリ毎に別ユーザに出来ない)
    • AuthGroupfile のグループ制御でどうにか出来んか?とも思ったけど require group xxx を自由に変えられない(htaccessが使えない)ので駄目
    • httpd-2.4 なら require で env を見たり式が使えたりするのでなんとでもなりそうだが…。

出来た

色々試行錯誤した経緯を端折って結果だけ書くと以下の様な設定で実現できた。

/etc/httpd/conf/httpd.conf
<Location /secret/>
    # とりあえず普通のBASIC認証設定
    AuthUserfile /path/to/docroot/secret/.htpasswd
    AuthGroupfile /dev/null
    AuthName "Secret"
    AuthType "Basic"
    require valid-user
    # ユーザ名と同名のディレクトリのみを許可する(ただしadminユーザは全てのディレクトリを閲覧可)
    RewriteEngine on
    RewriteCond %{REMOTE_USER},%{REQUEST_URI} !^([A-Za-z0-9_-]+),/secret/\1/
    RewriteCond %{REMOTE_USER} !=admin
    RewriteRule . - [F,E=retry_basic]
    Header set WWW-Authenticate "Basic realm=\"Secret\"" env=retry_basic
</Location>

制限事項が1つあり、ディレクトリ毎のユーザ名はディレクトリ名と同名のユーザ名が強制される。
その点さえ目をつぶれば、新規ディレクトリを作ったら .htpasswd にディレクトリ名と同じユーザとパスワードを追加するだけで良い。また、管理者はディレクトリ毎にユーザ名を変えてみるのは面倒だと思うので admin というユーザ名はディレクトリ名の縛りが効かないようにした。

力技ポイント

valid-user が通ったユーザに対して改めてBASIC認証をやり直させる方法

  • require valid-user が通ったユーザに対して、mod_rewrite で改めてユーザ名とディレクトリ名の不一致をチェックして強制的に 403 Forbidden を返す。
  • また F と同時に環境変数を介して Header set と連携し、単に 403 にするだけでなく、BASIC認証の要求ヘッダを出力する。
  • これにより valid-user であるにも関わらず、ブラウザには改めてBASIC認証の入力ダイアログが表示されることになる。

地味に面倒だった 『ディレクトリ名とユーザ名の一致チェック』

  • RewriteCond %{REQUEST_URI} ^/secret/%{REMOTE_USER}/ とかどうだ?
    • %{REMOTE_USER}{} の部分が正規表現エラー。まぁそうよね…。
  • RewriteCond %{REQUEST_URI} ^/secret/%\{REMOTE_USER\}/ だと?
    • %{REMOTE_USER} っていう文字列そのままの名前のディレクトリにマッチしちゃう。ですよねー…。
  • RewriteCond %{REQUEST_URI} ^/secret/([^/]+) して更に RewriteCond %{REMOTE_USER} %1 とか後方参照で分けたらどうよ!?
    • → ちょっと期待してたんだが %1 ていう2文字の名前のBASIC認証ユーザ名が通るようになったよ!
    • つまり第2引数に変数入れられないってことなんだな…。しかしそれだと REQUEST_URI と REMOTE_USER を比較する方法ってあるんか?

💡 ピコーン! そういえば RewriteCond の第1引数って単なる文字列だから変数2つとも突っ込んで、1個の正規表現の中で後方参照使って2箇所に分かれた部分文字列の一致チェックをすればいいんじゃね!?
ってことで ↓ この1行マッチが生まれた。

RewriteCond %{REMOTE_USER},%{REQUEST_URI} !^([A-Za-z0-9_-]+),/secret/\1/

結果は見事成功。やったね! 🎉

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3