mod_mrubyの認証機能について(応用編1)

実際に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つの例も書きます。

Nazy の紹介

A software engineer.
カテゴリー: mruby, Programming タグ: パーマリンク