Apache のDigest認証って便利なんだけど
Apache のパスワード認証がSQLで出来たら楽じゃん。htpasswd コマンドでファイルを置いておくと、管理が面倒になってきて書き散らかす。なにより有効期限とか決めたいじゃん。
かといってLDAPを聞いたりPAMに投げるのは、PAM・LDAPにガンガンユーザー増やすことになって本意じゃないし。なんかいい方法ないかとApacheのDocumentをあさってたら dbd とか便利そうなの見つけた。
Fileの代わりにデータベース(SQL:RDMBS)を使える。
mod_db 使ってみた。
mod_db で認証をSQLで連携できる
仕組みとしてはApacheにDigest(Basic)認証で、パスワードをファイルじゃなく、RDBMSでSQLを使うことになる。
mod_dbd を使うことで、次のようなパスワード連携が可能になる。
httpリクエスト→ directory → 認証 → DB へ問合せ (SQL
ただし、パスワードの形式は、Basic/Digestで使うパスワード形式になるので注意が必要。
Apacheのmod_auth の命名規則
命名規則 | 意味 |
---|---|
mod_auth_XXXX | 認証方法(標準はbasic,digest,formしかない) |
mod_authn_XXXX | 認証バックエンド(要はユーザーデータベース) |
mod_authz_XXXX | 承認(アクセス制御)を提供 |
mod_authnz_XXX | 認証・承認のどちらも |
承認については、セキュリティ屋は認可と呼んでる。一般的にはアクセス許可と呼ばれる。
設定について
DB 連携でApacheの認証をするには、いろいろ前提条件があるので整理しておく。
前提条件 mod_authnz_dbd mod_dbd 設定の記述場所 httpd.conf / virtualhost データベースの保存先 /Users/takuya/Sites/dbdExample/users.sqlite3.db 認証で保護するURL http://localhost/~takuya/dbdExample/ 認証方式 Basic
digest でも良いんだけど動作確認のために、Basicでやりました。通常はDigestを使う。
用語の整理 dbd => DataBaseDriver の略
基本設定 モジュールロード
まず、始めに、apacheでモジュールをロードしておく
今回使ったApacheはOSXにバンドルされているApache2.4です
takuya@~/Sites/dbd$ httpd -V Server version: Apache/2.4.16 (Unix) Server built: Aug 22 2015 16:51:57 Server's Module Magic Number: 20120211:47 Server loaded: APR 1.4.8, APR-UTIL 1.5.2 Compiled using: APR 1.4.8, APR-UTIL 1.5.2 Architecture: 64-bit Server MPM: prefork threaded: no forked: yes (variable process count) Server compiled with.... -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_FLOCK_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=256 -D HTTPD_ROOT="/usr" -D SUEXEC_BIN="/usr/bin/suexec" -D DEFAULT_PIDLOG="/private/var/run/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="/private/etc/apache2/mime.types" -D SERVER_CONFIG_FILE="/private/etc/apache2/httpd.conf"
httpd.conf でモジュールをロード
dbd と authnz_dbd をロードしておく。
takuya@~/Sites/dbd$ grep dbd /etc/apache2/httpd.conf 69:LoadModule authn_dbd_module libexec/apache2/mod_authn_dbd.so 94:LoadModule dbd_module libexec/apache2/mod_dbd.so
ロード設定を書いたら、ロードが正しく出来るか、チェックする
sudo apachectl -k restart
基本設定 データベースドライバの指定
今回は、/etc/apache2/users/takuya.conf にある。 ユーザーディレクトリの設定に書いた
takuya.conf は httpd.conf からIncludeされるだけなので、httpd.conf の領域に書いたことになる。
/etc/apache2/users/takuya.conf
DBDriver sqlite3 DBDParams "/Users/takuya/Sites/dbdExample/users.sqlite3.db"
設定が出来たら、DBDriverが存在スルかチェックするために再起動。
sudo apachectl -k restart
認証設定
ここ迄が無事終わったら、認証設定をして当該ディレクトリに認証設定を施す。
DBDriver sqlite3 DBDParams "/Users/takuya/Sites/dbdExample/users.sqlite3.db" <Directory /Users/takuya/Sites/dbdExample > Authtype Basic AuthName "takuya's private " AuthBasicProvider dbd require valid-user AuthDdbUserPwQuery "SELECT password from users where user = %s " </Directory>
設定を追加したら、認証設定を有効にするために、一旦再起動をしておく。
sudo apachectl -k restart
再起動が終わったら、認証設定が有効になっているか、アクセスして確認しておく
takuya@~/Sites/dbd$ curl http://localhost/~takuya/dbdExample/index.php <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>401 Unauthorized</title> </head><body> <h1>Unauthorized</h1> <p>This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.</p> </body></html>
curl でアクセスして、認証設定がオンになっていて、401が返って来てることがわかる。
ブラウザでアクセスしてもいい。Basic認証のダイアログが出てきたら成功
ついでに、適当なパスワードで認証して実験しておく
curl -I http://takuya:mypass@localhost/~takuya/dbdExample/index.php HTTP/1.1 401 Unauthorized Date: Fri, 13 Nov 2015 11:39:23 GMT Server: Apache/2.4.16 (Unix) Phusion_Passenger/5.0.8 PHP/5.5.29 WWW-Authenticate: Basic realm="takuya's private " Content-Type: text/html; charset=iso-8859-1
これで、データベースさえ準備すればイイ前提条件が整った。
このときのApacheのエラーログを確認すると・・・
(日付省略) Internal error: AH00629: Can't connect to sqlite3: unable to open database file (日付省略) Internal error: AH00633: failed to initialise (日付省略) AH01653: Failed to acquire database connection to look up user 'takuya'
データベースが見つからないとか、takuya ユーザーのパスワードは取れなかったとか、期待通りにエラーが出てきている。
ここで、はじめてデータベースを作る準備が整った
データベースを作る
データベースをとりあえず、ぱぱっと作る
sqlite3 /Users/takuya/Sites/dbdExample/users.sqlite3.db
sqlite3 コマンドでCREATE TABLEを実行する
SQLite version 3.8.11.1 2015-07-29 20:00:57 Enter ".help" for usage hints. >>CREATE TABLE users ( user varchar(255) not null unique , password varchar(255) not null, );
とりあえず超シンプルなデータベースとテーブルを用意した
テーブルにユーザを作る。
テーブルにユーザを作る。
insert into users ( user , password ) values ("takuya","takuya");
このパスワードは平文でとりあえず入れている。(エラーになるはず、データベースが見つからないエラは消えるはず)
これでユーザを作れたので、実際にアクセスしてみる
takuya@~/Sites/dbd$ curl -I http://takuya:takuya@localhost/~takuya/dbdExample/index.php HTTP/1.1 401 Unauthorized Date: Fri, 13 Nov 2015 11:44:28 GMT Server: Apache/2.4.16 (Unix) Phusion_Passenger/5.0.8 PHP/5.5.29 WWW-Authenticate: Basic realm="takuya's private " Content-Type: text/html; charset=iso-8859-1
認証は、通らない。(これはパスワードを平文で入れているため)
この時のApacheのエラーログを確認すると
(日付省略) AH01617: user takuya: authentication failure for "/~takuya/dbdExample/index.php": Password Mismatch
エラーのログは「Password Mismatch」に変わった。
これで、データベースへの参照は正しく行われたことがわかる。
apacheが解釈できるパスワードを作る
今回はBasic認証をすることにしたので、Basic認証用のパスワードを作る
作り方はhtpasswd を使うのが早い。
htpasswd -n ユーザー名
実際にヤってみたものが以下のとおりに。
takuya@~$ htpasswd -n takuya New password: Re-type new password: takuya:$apr1$tXIGze4Z$EaCVCt9GTlSpXAUTEwk1x.
パスワードをテーブルに登録。
先程は、適当な平文パスワードを入れたので、Basic認証用で使えるパスワード文字列に変更する
SQLite version 3.8.11.1 2015-07-29 20:00:57 Enter ".help" for usage hints. >> update users set password = '$apr1$tXIGze4Z$EaCVCt9GTlSpXAUTEwk1x.' where user = "takuya"; >>
これで、users テーブルの中にあるパスワードが更新された。
ここまでで、完璧に予定通り来ているので、最後に認証を通してみる。
認証データ付きでアクセスしてみる
さて、これでうまくいくとほぼ確信しつつ、認証を通してみる。
takuya@~/Sites/dbd$ curl -I http://takuya:takuya@localhost/~takuya/dbdExample/index.php HTTP/1.1 200 OK Date: Fri, 13 Nov 2015 11:51:25 GMT Server: Apache/2.4.16 (Unix) Phusion_Passenger/5.0.8 PHP/5.5.29 X-Powered-By: PHP/5.5.29 Content-Type: text/html
無事アクセス出来るようになった。やったね。
アクセスはCurlでおこなったけど、ブラウザで確認してもいい。
テーブル構造を変化させてみる。
Apacheが実行するSQLは、directory ディレクティブに記述した次のSQLになる。
AuthDdbUserPwQuery "SELECT password from users where user = %s "
SQLでカラムを指定してるだけ。つまりだ、コレ以外にカラムがあったって問題ないわけですよね。
テーブル構造を変更してみる。
CREATE TABLE users ( id integer primary key, user varchar(255) not null unique , password varchar(255) not null, created_at timestamp default current_timestamp not null, expires timestamp );
このようなテーブルに変えてみた。もちろんチャント動く。
SQLite 以外のRDBMSを使う。
mod_dbd のドライバをインストールしていれば
などもチャント動くようです。ドライバがインストールされてて、コネクションできてSQLが実行できればなんでもイイみたい。
SQL をアレンジしてみる。
AuthDdbUserPwQuery \ "SELECT password from users \ where user = %s \ and expires > current_timestamp"
このようにすれば、アクセスユーザーを増やしても、アクセス期限を設定することが出来て、ユーザーの管理や削除を忘れておける。便利!
このユーザは、いつ、なんのため、いつまで有効か、をコメントで入れなくてもいい。テーブルで管理できる。そして期限が来ても削除する必要がなくてイイ。
htpasswd ファイルとさようなら
はじめて「ホームページ」を作ったアノ頃からお世話になった.htpasswd に別れを告げる時のようだ。
これで、htpasswd ファイルとサヨナラできる。大学生新入生時代から10年近くAapache使ってるけど、ようやく、理解できた。