Tags: ,
Posted by: peter

Kurt Grandis carried out an awesome Django vs .NET experiment at his company:

Almost two years ago I was in a rather unlikely situation in that I was running a software engineering department containing both a C# team and a Python team…It slowly dawned on me that I had a perfect test bed. Here we had two teams using different technology stacks within the same department…they shared the same development processes, project management tools, quality control measures, defect management processes. Everything was the same between these groups except for the technologies. Perfect! So like any good manager I turned my teams into unwitting guinea pigs.
With the result:
We found the average productivity of a single Django developer to be equivalent to the output generated by two C# ASP.NET developers. Given equal-sized teams, Django allowed our developers to be twice as productive as our ASP.NET team.
Posted by: peter
Today I needed to make one of my Django sites authenticate against the same usebase as one of my FreeRADIUS servers. Now, given that the RADIUS userbase is in PostgreSQL, this could have been done without touching RADIUS per se, however that would not have been nearly as interesting or elegant as making Django speak RADIUS. (And given the strange record format that FreeRADIUS uses, would have taken nearly as long to implement) After about half an hour of hacking on a Django custom Authentication Backend I now have a Django happily authenticating from my FreeRADIUS server with all the flexibility that implies (Being able to proxy requests to third parties, set time of day restrictions, use multiple clustered backends etc etc). Without further ado, here is the first cut:
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:
    """
    Authenticate against a RADIUS Server.

    You must have a working RADIUS Server and Secret
    configured in settings.py. For example:

    RADIUS_SERVER = '127.0.0.1'
    RADIUS_SECRET = 'testing123'
    """
    def authenticate(self, username=None, password=None):

        srv=Client(server=settings.RADIUS_SERVER, 
                        secret=settings.RADIUS_SECRET,
                        dict=Dictionary("/usr/share/pyrad/dictionary"))

        req=srv.CreateAuthPacket(code=pyrad.packet.AccessRequest)
        req["User-Name"] = username
        req["User-Password"] = req.PwCrypt(password)
        req["NAS-Identifier"] = "django"

        reply=srv.SendPacket(req)
        if reply.code==pyrad.packet.AccessAccept:
            print "access accepted"
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. Note that we can set password
                # to anything, because it won't be checked; the password
                # configured on the RADIUS server will.
                user = User(username=username, password='Koh8oF7eiRou4xahxoob')
		#TODO: Use user.set_unusable_password() once
                # Django SVN > 5608 + openSUSE 10.3 bug is fixed
                user.is_staff = False
                user.is_superuser = False
                user.save()
            return user
        else:
            print "access denied"
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None
Just copy and paste this code into myproj/radiusauth.py and then stick the following in settings.py:
AUTHENTICATION_BACKENDS = (
    'myproj.radiusauth.RadiusBackend',
    'django.contrib.auth.backends.ModelBackend',
)
This code makes use of Wiggy’s wonderfull Pyrad library, so you will need to have it installed also to make things work.