Djangoの認証をActive Directoryで

Djangoを使った社内アプリで、ユーザ登録を自分でやってもらうところまで出来たんだけど、このアプリのためにIDとパスワードを覚えるのがめんどくさい。
社内で Active Directory が動いているんだから、それを使って認証できないか試してみたらなんとなく動いてるのでメモしておく。
WinXP(2003 Server), Python 2.4.4, Django 0.96, Python-LDAP 2.0.6 for Python 2.4 で動作確認済み。

認証バックエンド

Djangoの認証を置き換えるのはすごい簡単なので、実際やるのはこれくらい。

  1. 認証バックエンドを作る。
    ここでは djangoproject/app/util.py に ActiveDirectoryBackend クラスを作成した。
    継承とかは必要なくて、authenticate(self, username, password) と get_user(self, user_id) を定義しておけばいい(引数名を一致させておかないと認証チェックしないみたい)。
  2. settings.py に AUTHENTICATION_BACKENDS を設定する。
    上から順番に認証が成功するまでトライしていくので、最初に ActiveDirectoryBackend クラスを指定する。

ちなみにコードはこんな感じ。
認証が成功した場合に、ユーザオブジェクトを作るようにしてある。

SERVER_ADDRESS は「pcname.xxx.co.jp」のようなADサーバのアドレスを、DOMAIN_NAME はADサーバが所属するドメイン名?を指定する。
環境によっては動かないかも。

#settings.py
AUTHENTICATION_BACKENDS = (
    'djangoproject.app.util.ActiveDirectoryBackend'
    'django.contrib.auth.backends.ModelBackend',
)

#djangoproject/app/util.py
class ActiveDirectoryBackend:
   def authenticate(self, username='', password=''):
       if not self.is_valid(username, password):
           return None

       try:
           user = User.objects.get(username=username)
       except User.DoesNotExist:
           user = User(username=username, password='dummy')
           user.save()
       return user

   def get_user(self, user_id):
       try:
           return User.objects.get(pk=user_id)
       except User.DoesNotExist:
           return None

   def is_valid(self, user='', password=''):
       try:
           l = ldap.open('SERVER_ADDRESS')
           l.simple_bind_s('%s@DOMAIN_NAME' % user, password)
           l.unbind_s()
           return True
       except ldap.LDAPError:
           return False