Digest 認証を行う Django の middleware を書いてみる

Python 自体そんなに触ったわけじゃないのでまだまだなことは百も承知でダイジェスト認証を行うための Django のミドルウェアを公開します。やさしくしてね。利用については、パブリック・ドメインであると解釈してください*1。パッケージ自体は、Django に依存する部分と、汎用的な、しかたなくフルスクラッチで書き下ろした RFC2617 ほぼ準拠のダイジェスト認証モジュールからなっています。

http://voltex.jp/downloads/Mozo.Django.DigestAuth-0.0.tar.gz

使いかた。

1. インストールする。

いちおう distutils をつかってパッケージングしてあります。センスのないモジュール名でごめんなさい。

2. プロジェクトの settings.py の MIDDLEWARE_CLASSES に 'mozo.django.middleware.auth.AuthDigestMiddleware' を追加。
MIDDLEWARE_CLASSES = (
    'mozo.django.middleware.auth.AuthDigestMiddleware',
    ...
)
3. 同 setting.py に項目 AUTH_DIGEST_ACCOUNT_MODEL と AUTH_DIGEST_REALM を追加。

AUTH_DIGEST_ACCOUNT_MODEL にはパスワードのハッシュを記録するモデル名を指定してください。このモデルは次のようなプロパティを持っている必要があります。

項目名 意味
username ユーザ名
pw_hash "<ユーザ名>:<レルム>:<パスワード>" からなる信用情報 *2MD5 ハッシュ。Apache付属の htdigest が生成してくれるヤツと覚えておけばおk。

AUTH_DIGEST_REALM にはレルム (Windows 用語でいう「保護領域」) を指定してください。ドメイン名とかが適当です。すみませんが、この実装では複数のレルムをデータベース上でユーザアカウントに関連づけることができていません。

設定例を以下に示します。

AUTH_DIGEST_ACCOUNT_MODEL = 'someproject.models.User'
AUTH_DIGEST_REALM = 'example.com'
4. モデルを pw_hash を格納するよう修正する。

デフォルトの auth アプリケーションのモデルを拡張するのってどうやるんだろう?とりあえずわたしは自分のモデルを作って試しましたが。

それにしても middleware の process_view()、微妙じゃね?

class AuthDigestMiddleware:
    ... 略 ...
    def process_view(self, request, view_func, view_args, view_kwargs):
        auth_params = self.try_auth(request)
        user = None
        if auth_params:
            user = self.manager.get(username=auth_params['username'])
        if not user:
            dreq = DigestAuthRequest(
                realm = settings.AUTH_DIGEST_REALM,
                nonce = generate_nonce(self.private_key),
                qop_list = ['auth'])
            return HttpResponseDigestAuth(dreq)
        #view_args = view_args + (user, self.provider)  # この行頭の「#」はご愛嬌
        view_kwargs['user']= user
        view_kwargs['provider'] = self.provider
        return None

(追記:意味不明な説明だったので直しました)
上のミドルウェアのコアな部分はこうなっています。ここで view_args や view_kwargs をいじったときに、続いて呼び出される view メソッド (view_func) の引数が新しく追加した引数に対応していないと「引数の数、ちゃうで」とランタイムエラーになっちゃう。これっていろいろなアプリケーションでミドルウェアを使いたいときに不便すぎるので何とかならないだろうかと思案中なわけです。

もちろん request や view_func で判別することはできますが、それっていい解決法とはいえないし…どなたか教えてください。

*1:ただし、日本には権利の所在としてのパブリック・ドメインという概念がないので、そういう意味では微妙ですが

*2:credential のこと