Django の認証を RADIUS で。

まずはじめに

記憶は削除の方向で - Djangoの認証をActive Directoryで
http://d.hatena.ne.jp/re_guzy/20070522/p1

を激しくインスパイアしています。

id:re_guzy さんのコードほぼそのままです。

かなり単純ですが、こんな事も出来るんだ程度でみていただけると幸いです。

=================
Django and RADIUS
=================

:os: debian 4.0 r0 
:version: 1.0.0
:author: voluntas


色々 インストール編
===================

* python 2.4.4
* freeradius 1.1.3
* pyrad 0.9

::

  aptitude install python2.4-dev python2.4 libsqlite3-dev freeradius

  wget django
  wget pysqlite2
  wget pyrad

.. wget 手抜き

freeradius 設定編
=================

/etc/freeradius/client.conf::

  変更する必要なし

  client 127.0.0.1 {
    secret = testing123
    shortname = localhost
    nastype = other
  }


/etc/freeradius/radiusd.conf::

  log_auth = yes
  log_auth_badpass = yes
  log_auth_goodpass = yes


/etc/freeradius/users::

  "volunats" Auth-Type := Local, User-Password == "voluntas"

radius 検証編
=============

radtest
-------

accept::

  radtest "voluntas" "voluntas" localhost 1645 testing123
  
  Sending Access-Request of id 143 to 127.0.0.1 port 1812
          User-Name = "voluntas"
          User-Password = "voluntas"
          NAS-IP-Address = 255.255.255.255
          NAS-Port = 1645
  rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=143, length=20


reject:: 

  radtest "ymasuda" "ymasuda" localhost 1645 testing123

  Sending Access-Request of id 147 to 127.0.0.1 port 1812
          User-Name = "ymasuda"
          User-Password = "ymasuda"
          NAS-IP-Address = 255.255.255.255
          NAS-Port = 1645
  Re-sending Access-Request of id 147 to 127.0.0.1 port 1812
          User-Name = "ymasuda"
          User-Password = "ymasuda"
          NAS-IP-Address = 255.255.255.255
          NAS-Port = 1645
  rad_recv: Access-Reject packet from host 127.0.0.1:1812, id=147, length=20

/var/log/freeradius/radius.log::

  Sat Jun  2 13:07:29 2007 : Auth: Login OK: [voluntas] (from client localhost port 1645)
  Sat Jun  2 13:07:31 2007 : Auth: Login incorrect: [ymasuda] (from client localhost port 1645)

django インストール編
=====================

/user/local/src/::
  
  tar xvfz Django-0.96.tar.gz
  
  python setup.py install

/home/user/::

  django-admin.py startproject radius
  cd radius
  touch urls.py

/radius/settings.py::

  DATABASE_ENGINE = 'sqlite3'
  DATABASE_NAME = 'radius.db'

  INSTALLED_APPS = (
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.sites',
      'django.contrib.admin',
  )

  AUTHENTICATION_BACKENDS = (
      'radius.utils.RadiusBackend',
      #'django.contrib.auth.backends.ModelBackend',
  )

/radius/urls.py::

  (r'^admin/', include('django.contrib.admin.urls')),


::

  python manage.py syncdb
  cp /usr/local/src/pyrad-0.9/example/dictionary ~/django/radius

:username: admin
:e-mail: admin@example.org
:password: admin


django プログラム編
===================

/project/utils.py::

  import socket, sys

  from django.conf import settings
  from django.contrib.auth.models import User

  import pyrad.packet
  from pyrad.client import Client
  from pyrad.dictionary import Dictionary

  class RadiusBackend:
    
    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='radius')
        user.is_staff = True
        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, username='', password=''):
        srv = Client(
          server='localhost',
          # default
          secret='testing123',
          dict=Dictionary('dictionary')
        )

        req = srv.CreateAuthPacket(
          code=pyrad.packet.AccessRequest,
          User_Name=username,
        )
        req['User-Password'] = req.PwCrypt(password)

        try:
          reply=srv.SendPacket(req)
        except pyrad.client.Timeout:
          print "RADIUS server does not reply"
          sys.exit(1)
        except socket.error, error:
          print "Network error: " + error[1]
          sys.exit(1)

        if reply.code == pyrad.packet.AccessAccept:
          return True
        else:
          return False


django 検証編
=============

runserver::

  python manage.py runserver
  

http://localhost:8000/admin/
----------------------------

:Username: admin
:Password: admin

reject されるので freeradius に admin を追加する

.. あえてパスワードを変更して登録

/etc/freeradius/users::
 
  "admin" Auth-Type := Local, User-Password == "adminadmin"

accept::

  /etc/init.d/freeradius restart

  radtest "admin" "adminadmin" localhost 1645 testing123

  Sending Access-Request of id 58 to 127.0.0.1 port 1812
          User-Name = "admin"
          User-Password = "adminadmin"
          NAS-IP-Address = 255.255.255.255
          NAS-Port = 1645
  rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=58, length=20

  Sat Jun  2 13:56:43 2007 : Auth: Login OK: [admin] (from client localhost port 0)


http://localhost:8000/admin/
----------------------------

パスワードは freeradius をみるので要注意

:Username: admin
:Password: adminadmin

色々変なところがあるかも:^P
ちょこちょこ修正はしていきます。