実際にmod_mrubyの認証を使ってみる応用編その1です。
今回はRails製プロジェクトマネジメントソフトウェアであるRedmineとApacheの認証を連動させてみます。
なお、DBとしてsqlite3を使用している場合限定です。
今回の記事の内容は、これがやりたかったからmod_mrubyに認証機能を加えようと思った動機でもあります。
MySQLを使っていれば、mod_perl+Redmine.pmを使うとか、mod_auth_mysqlを使うとかの方法もあるんですけどね。
さて、Redmineのユーザ情報を使った認証をmod_mrubyで実現する方法は2つほど思いつくのですが、今回はRedmineのdbをsqlite3コマンド経由で呼び出して認証する方法を紹介します。
簡易なので、ユーザの所属プロジェクトやロールなどの属性は気にしていません。
sqlite3コマンド経由の簡易Redmine認証
準備:
- mrubyからプロセスを起動したり、ハッシュの計算をするのでiij/mruby版のmod_mrubyをApacheに組み込んでおきます。
- Basic認証をするので、Redmineの認証と連動したい<Location>または<Directory>にmod_mrubyのBasic認証定義を書いておきます。
考え方:
- sqlite3のdbにsqlite3コマンド経由でアクセスし、csv形式で情報を取得
- 取得した情報とパスワードを照合
スクリプトは以下のようになります。
# アクセスするsqlite3のdbファイルのパスを指定する
DB_PATH="/path/to/db.sqlite3"
def main()
anp = Apache::AuthnProvider.new
# ユーザ名がRedmineのレギュレーションを満たしているか、あらかじめ確認します。
# SQLを直接生成しているので、SQLインジェクション対策でもあります。
# if !~ ではなく、unnless =~ をつかっているのは、!~演算子が実装されていないからです。
unless anp.user =~ /^[a-z0-9_\-@\.]*$/
# Invalid format for redmine users
return Apache::AuthnProvider::AUTH_DENIED
end
# userに対応するhashed_passwordとsaltを取得する
hashed_password = salt = nil
cmd = %Q!sqlite3 -csv "#{DB_PATH}" "select hashed_password, salt from users where login='#{anp.user}' and users.status=1;"!
IO.popen(cmd) {|f|
line = f.gets
if line.nil?
# No such user
return Apache::AuthnProvider::AUTH_DENIED
end
hashed_password, salt = line.strip.split(",",2)
}
# RedmineのやりかたでパスワードをHash化して比較
if hashed_password == Digest::SHA1.hexdigest("#{salt}#{Digest::SHA1.hexdigest(anp.password)}")
return Apache::AuthnProvider::AUTH_GRANTED
else
return Apache::AuthnProvider::AUTH_DENIED
end
end
Apache.return(main())
これで認証が連動できます。
mrubyにSQLite3を組み込むと、もっと性能出るし書きやすくなりますが、現状ではここまで。
近いうちに、もう1つの例も書きます。