Tag: google apps

Django Google Apps Authentication

Django has an excellent user management and authentication system built into the framework. With it you can easily create users that can be authenticated against the website. But there are times when you just need to authenticate against a different system. In the case of an app I recently developed, I originally wanted to authenticate against an OS X Server. The OpenDirectory service on OS X Server is an LDAP server, under the hood you’ll find slapd from OpenLDAP running. So should be pretty straight forward to create an authentication module that uses Python’s LDAP module. And this article from the Carthage WebDev site shows you how to do it.

After I got the ldap_auth.py module working on my site, I realized the site would be better served if the authentication happened against Google Apps. Since Google Apps is currently being used by the organization for email, calendaring and sharing documents, everyone already has an account there. And with the ldap_auth.py module from Carthage Webdev, I thought it would be pretty simple to provide a google_auth.py module.

To get started, I had to install gdata. The installation instructions found on the Google Apps APIs page were pretty easy to follow. Specifically, I had to install the Provisioning API.

On a side note, I’m using Python 2.5 as installed via MacPorts. Before I could use the gdata APIs, I had to install py25-socket-ssl.

The APIs are pretty well documented via the examples from the Python Developer’s Guide. Here’s how I’m authenticating a Django project with users on Google Apps.

To start, there are three configuration variables that I added to the Django project’s settings.py module:

# Google Apps Settings
GAPPS_DOMAIN = 'your_domain.com'
GAPPS_USERNAME = 'name_of_an_admin_user'
GAPPS_PASSWORD = 'admin_users_password'

These will allow the module to authenticate against Google Apps and ask for specific details about the user.

Here’s the code for google_auth.py:

import logging
from django.contrib.auth.models import User
from django.conf import settings
from gdata.apps.service import AppsService, AppsForYourDomainException
from gdata.docs.service import DocsService
from gdata.service import BadAuthentication
 
 
logging.debug('GoogleAppsBackend')
 
 
class GoogleAppsBackend:
    """ Authenticate against Google Apps """
 
     def authenticate(self, username=None, password=None):
         logging.debug('GoogleAppsBackend.authenticate: %s - %s' % (username, '*' * len(password)))
         admin_email = '%s@%s' % (settings.GAPPS_USERNAME, settings.GAPPS_DOMAIN)
         email = '%s@%s' % (username, settings.GAPPS_DOMAIN)
 
         try:
             # Check user's password
             logging.debug('GoogleAppsBackend.authenticate: gdocs')
             gdocs = DocsService()
             gdocs.email = email
             gdocs.password = password
             gdocs.ProgrammaticLogin()
             # Get the user object
 
             logging.debug('GoogleAppsBackend.authenticate: gapps')
             gapps = AppsService(email=admin_email,
                                 password=settings.GAPPS_PASSWORD,
                                 domain=settings.GAPPS_DOMAIN)
             gapps.ProgrammaticLogin()
             guser = gapps.RetrieveUser(username)
 
             logging.debug('GoogleAppsBackend.authenticate: user - %s' % username)
             user, created = User.objects.get_or_create(username=username)
 
             if created:
                 logging.debug('GoogleAppsBackend.authenticate: created')
                 user.email = email
                 user.last_name = guser.name.family_name
                 user.first_name = guser.name.given_name
                 user.is_active = not guser.login.suspended == 'true'
                 user.is_superuser = guser.login.admin == 'true'
                 user.is_staff = True
                 user.save()
 
         except BadAuthentication:
             logging.debug('GoogleAppsBackend.authenticate: BadAuthentication')
             return None
 
         except AppsForYourDomainException:
             logging.debug('GoogleAppsBackend.authenticate: AppsForYourDomainException')
             return None
 
         return user
 
 
     def get_user(self, user_id):
 
         user = None
         try:
             logging.debug('GoogleAppsBackend.get_user')
             user = User.objects.get(pk=user_id)
 
         except User.DoesNotExist:
             logging.debug('GoogleAppsBackend.get_user - DoesNotExist')
             return None
 
         return user

It was pretty easy to write and debug this code using the ldap_auth.py module as a working example.

One downside to this code is that any newly created users in the Django auth database don’t have any rights. So if the Django project is expecting to be able to dynamically change the contents based on the rights that the user has, the account will have to manually modified via the Django admin interface. Not too bad, but annoying.

Tags : , ,