2011-12-06

OpenVPN sqlite認証プラグイン

By Taro Yamazaki  |  20:00

English version is here.

OpenVPNでsqliteをデータベースとして使用し、ID/パスワードを使って認証するためのプラグインです。pythonで書かれていますので、必要に応じて変更してお使いください。
このプラグインは無保証で提供されています。ご利用の環境によっては正しく動作しない可能性があります。また、このプラグインの使用によって生じた損害(直接、間接を問わず)の責任を作者は一切負いません。

使用方法

ユーザーデータベースの準備
認証に使用するユーザーIDとパスワードを保持するsqliteデータベースファイルを用意します。サンプルデータベースではデータベースのテーブル名は「Users」、IDを「UserId」フィールド、パスワードを「Password」フィールド、有効/無効フラグを「Active」フィールドに設定していますが、auth-sqlite.py内のSQLを書き換えれば任意のスキーマに対応できます。

UserIdPassword Active
gonbenaisho#00231
jdoeDa-reMO_shiRANA11
harukaQueenS#1*21
hidemonkey%55!0
  • Windows上でsqliteデータベースを扱うにはPupSQLiteがお手軽でお勧めです。
  • 上のテーブルではパスワードを平文で記載していますが、データベース内に格納するパスワードはRIPEMD160でハッシュ化します。ブラウザでのハッシュ化にはこのサイトが便利です(出力結果の「hex」を使います)。
プラグインファイルの配置
auth-sqlite.pyをOpenVPNサーバーに設置します。通常は/etc/openvpnの中などがわかりやすいと思います。このとき、auth-sqlite.py実行権限を付与しておくことを忘れないようにしてください。
OpenVPNサーバー設定ファイルの編集
OpenVPNサーバー設定ファイルに以下の記述を追加します。
script-security 2
client-cert-not-required
username-as-common-name
setenv auth_sqlite_db /etc/openvpn/vpnusers.db
auth-user-pass-verify /etc/openvpn/auth-sqlite.py via-file

script-security 2
プラグインとして外部プログラムを呼び出す際にはこの値を2か3に設定する必要があります。この設定のデフォルト値は1で、この場合はifconfigrouteコマンドなどのOS組み込みコマンドしか実行できません。
client-cert-not-required
クライアント証明書による認証を不要にします。ID/パスワードのみで認証するようにしたいときにはこのディレクティブが必要です。
username-as-common-name
認証で使用するユーザー名(ID)を証明書の共通名(common name)として使用します。これは特にCCD(クライアント構成ディレクトリ:Client Configuration Directory)を使用する際などに必要になります。
setenv auth_sqlite_db /etc/openvpn/vpnusers.db
ユーザーデータベースとして使用するsqliteデータベースファイルをauth_sqlite_dbという環境変数に設定します。スクリプト内でこの環境変数に設定された値を読み込み、データベースに接続します。
auth-user-pass-verify /etc/openvpn/auth-sqlite.py via-file
認証プラグインとして使用するファイルの位置をフルパスで指定します(スクリプトの場合はpluginディレクティブではないのでご注意を)。2番目の引数は、認証情報をOpenVPNからスクリプトに受け渡す方法を指定します。「via-file(ファイル経由)」か「via-env(環境変数経由)」のいずれかになります。
OpenVPNクライアントから接続!
OpenVPNクライアントから接続を試してみましょう。auth-user-passディレクティブを指定し、ID/パスワード認証を使用するように設定します。設定が簡単な vpnux Connector Lite がお勧めです。
サーバーのログ
OpenVPNサーバーのログには認証結果が以下のように記録されています。まずは認証に成功した場合。最後から2番目の行の数字は、データベースを検索した結果、IDとパスワードでの検索でヒットした行数です(つまり「1」なら認証OKということですね)。
[auth-sqlite] sqlite_file : /etc/openvpn/vpnusers.db
[auth-sqlite] filename : /tmp/openvpn_up_a4f9bc76dbe81514ae0628285c328616.tmp
[auth-sqlite] username : hide
[auth-sqlite] password : monkey%55!
[auth-sqlite] hashedPassword : f5d003945021de1e376559db7fc13b227ae1792d
1
[auth-sqlite] Authentication succeed.
そして認証に失敗した場合です。
[auth-sqlite] sqlite_file : /etc/openvpn/vpnusers.db
[auth-sqlite] filename : /tmp/openvpn_up_ebd6f2c1fa0662a4cf2b160f50b835a7.tmp
[auth-sqlite] username : hide
[auth-sqlite] password : damedame*password
[auth-sqlite] hashedPassword : a6f144628d9619d725397e8cce709288d5ad81e1
0
[auth-sqlite] Authentication failed.
認証に成功した場合は終了コード 0で、認証に失敗した場合は終了コード 1で終了させると、その終了コードを受け取ったOpenVPNサーバーが認証結果をクライアントに送信します。

ソースコード:auth-sqlite.py

#!/usr/bin/python
import os
import sys
import hashlib
try:
    import sqlite3
except:
    from pysqlite2 import dbapi2 as sqlite3

## Read settings from config
sqlite_file = os.environ["auth_sqlite_db"]
print "[auth-sqlite] sqlite_file : " + sqlite_file

## Read username and password from via-file
filename = sys.argv[1]
print "[auth-sqlite] filename : " + filename
fp = open(filename)
data = fp.readlines()
fp.close()
username = data[0].rstrip()
password = data[1].rstrip()
print "[auth-sqlite] username : " + username
print "[auth-sqlite] password : " + password
h = hashlib.new("ripemd160")
h.update(password)
hashedPassword = h.hexdigest()
print "[auth-sqlite] hashedPassword : " + hashedPassword

## Connect and fetch from database
vals = (username, hashedPassword)
conn = sqlite3.connect(sqlite_file)
cur = conn.cursor()
cur.execute('SELECT count(*) FROM Users WHERE UserId = ? AND Password = ? AND Active = 1', vals)
row = cur.fetchone();
targetRows = row[0]
conn.close()

print targetRows

## Return result
if(targetRows == 1):
 print "[auth-sqlite] Authentication succeed."
 sys.exit(0)
else:
 print "[auth-sqlite] Authentication failed."
 sys.exit(1)

sys.exit(1)

Author: Taro Yamazaki

© 2015 yamata::memo | Distributed By My Blogger Themes | Created By BloggerTheme9
TOP