2008.02.22 Friday
Basic認証の認証領域 〜AuthName はただのテキストに非ず〜
とある管理画面へのアクセス制限のために, 管理画面のディレクトリ(admin)以下に Basic認証をかけることになったのですが,
特定のサブディレクトリ(ex)には別のユーザ/パスワードの組で Basic認証をかけたいという要望がありました。
単純に .htaccess で別々に Basic認証の定義をしてやれば解決...なはずでしたが,
admin 以下にアクセス(Basic認証) ⇒ admin/ex 以下にアクセス(Basic認証)
この後 admin 以下にアクセスするとまた Basic認証のダイアログが。
さらに admin/ex 以下にアクセスするとまた Basic認証のダイアログが。
さらに admin 以下(略。
と, admin ⇔ admin/ex を移動する度に認証を求められて非常に難儀。
認証されたらブラウザ閉じるまでは有効なんじゃなかったっけ。
「なんで Basic認証すぐ切れてしまうん?」
特定のサブディレクトリ(ex)には別のユーザ/パスワードの組で Basic認証をかけたいという要望がありました。
単純に .htaccess で別々に Basic認証の定義をしてやれば解決...なはずでしたが,
admin 以下にアクセス(Basic認証) ⇒ admin/ex 以下にアクセス(Basic認証)
この後 admin 以下にアクセスするとまた Basic認証のダイアログが。
さらに admin/ex 以下にアクセスするとまた Basic認証のダイアログが。
さらに admin 以下(略。
と, admin ⇔ admin/ex を移動する度に認証を求められて非常に難儀。
認証されたらブラウザ閉じるまでは有効なんじゃなかったっけ。
「なんで Basic認証すぐ切れてしまうん?」
結論から言うと, 原因は AuthName と AuthUserFile。
admin と admin/ex の .htaccess はそれぞれ以下のようになっていました。
・admin/.htaccess
・admin/ex/.htaccess
AuthName は共に "Input ID and Password." ですが, AuthUserFile の指定先が違っていて, Basic認証のユーザも別々に定義されていました。
何故この設定でプチプチ Basic認証が途切れてしまうか, ですが, ただのテキストだと思っていた AuthName が認証領域という役割を果たしていたからです。
Webサーバは認証領域(AuthName)に対して ユーザ名/パスワード を求めてリソースへのアクセス許可の判断をします。
これはレスポンスヘッダを見れば明らかです。
WWW-Auhenticateヘッダの realm の部分に AuthName の文字列が書いてあります。
この realm("Input ID and Password.")に対して認証が必要です, とサーバが応答しているのです。
今の今まで, AuthName って認証ダイアログの説明文だとずっと信じてたのに...(;´∀`)
さて, ユーザ名/パスワードを入力したリクエストヘッダは以下になります。
Authorizationヘッダの部分が, 入力したユーザ名/パスワードをコロンで繋いで BASE64エンコードしたものです。
一度認証すればこの値をブラウザが覚えていてくれるので, 認証領域以下のディレクトリにアクセスすると毎回リクエストヘッダに自動的に付加されます。
ここまで理解できれば, 上で挙げた設定が何をしていたかは自明。
AuthName(realm)が同じなので, 同じ認証領域の認証設定を定義していたに過ぎません。
違うのはユーザ名/パスワードの組。
となると admin と admin/ex は同じ認証領域なのに Authorizationヘッダ値は異なることになります(ユーザ名とパスワードが異なるから当たり前ですが)。
ブラウザが記憶できるユーザ名/パスワードの組は 1つの認証領域(realm)に対して 1つだけ。
だから admim ⇔ admin/ex 間で毎回認証を求められていたのです。
これを回避するには, admin/ex に別の認証領域を設定を設定してやれば OK。
(.htpasswd_admin に .htpasswd_admin_ex のユーザ名/パスワードを追加しても大丈夫ですが, 別の AuthName を定義する方がすっきりします)
AuthName を "[ex] Input ID and Password." とでもしてやれば, 認証領域毎にブラウザが適切な Authorizationヘッダを付けてくれるようになります。
教訓:「AuthName はただのテキストに非ず」
Wikipedia:『Basic認証』
Apache 2.0 ドキュメント:『認証、承認、アクセス制御』
admin と admin/ex の .htaccess はそれぞれ以下のようになっていました。
・admin/.htaccess
AuthUserFile /path/to/.htpasswd_admin
AuthName "Input ID and Password."
AuthType Basic
require valid-user
・admin/ex/.htaccess
AuthUserFile /path/to/.htpasswd_admin_ex
AuthName "Input ID and Password."
AuthType Basic
require valid-user
AuthName は共に "Input ID and Password." ですが, AuthUserFile の指定先が違っていて, Basic認証のユーザも別々に定義されていました。
何故この設定でプチプチ Basic認証が途切れてしまうか, ですが, ただのテキストだと思っていた AuthName が認証領域という役割を果たしていたからです。
Webサーバは認証領域(AuthName)に対して ユーザ名/パスワード を求めてリソースへのアクセス許可の判断をします。
これはレスポンスヘッダを見れば明らかです。
HTTP/1.0 401 Authorization Required
Date: Fri, 22 Feb 2008 13:36:02 GMT
Server: Apache
WWW-Authenticate: Basic realm="Input ID and Password."
Content-Length: 401
Content-Type: text/html; charset=iso-8859-1
WWW-Auhenticateヘッダの realm の部分に AuthName の文字列が書いてあります。
この realm("Input ID and Password.")に対して認証が必要です, とサーバが応答しているのです。
今の今まで, AuthName って認証ダイアログの説明文だとずっと信じてたのに...(;´∀`)
さて, ユーザ名/パスワードを入力したリクエストヘッダは以下になります。
GET /admin/index.html HTTP/1.0
Accept: */*
Accept-Language: ja
Pragma: no-cache
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1);
Host: php.y-110.net
Authorization: Basic dGVzdDpob2dlaG9nZQ==
Authorizationヘッダの部分が, 入力したユーザ名/パスワードをコロンで繋いで BASE64エンコードしたものです。
一度認証すればこの値をブラウザが覚えていてくれるので, 認証領域以下のディレクトリにアクセスすると毎回リクエストヘッダに自動的に付加されます。
ここまで理解できれば, 上で挙げた設定が何をしていたかは自明。
AuthName(realm)が同じなので, 同じ認証領域の認証設定を定義していたに過ぎません。
違うのはユーザ名/パスワードの組。
となると admin と admin/ex は同じ認証領域なのに Authorizationヘッダ値は異なることになります(ユーザ名とパスワードが異なるから当たり前ですが)。
ブラウザが記憶できるユーザ名/パスワードの組は 1つの認証領域(realm)に対して 1つだけ。
だから admim ⇔ admin/ex 間で毎回認証を求められていたのです。
これを回避するには, admin/ex に別の認証領域を設定を設定してやれば OK。
(.htpasswd_admin に .htpasswd_admin_ex のユーザ名/パスワードを追加しても大丈夫ですが, 別の AuthName を定義する方がすっきりします)
AuthName を "[ex] Input ID and Password." とでもしてやれば, 認証領域毎にブラウザが適切な Authorizationヘッダを付けてくれるようになります。
教訓:「AuthName はただのテキストに非ず」
Wikipedia:『Basic認証』
Apache 2.0 ドキュメント:『認証、承認、アクセス制御』









Comments