Google Apps Auth for Internal Django Sites

Usernames and passwords are lame. Everything that makes them lame on the wider web makes them doubly lame on your company intranet. Here’s how we stopped writing password reset forms.

At Safari, we’ve been trying to make it easier to prototype little applications to show to our colleagues. At the start of the year, we also switched the entire company to Google Apps for Business. While this has mostly been a win for our IT staff and coworkers (with some major exceptions), the range of APIs and developer-focused services provided by Google is tremendous. In particular, it is incredibly straightforward to wire together Django, the django-social-auth package, and Google’s OAuth 2.0 identity service to create secure web applications that are only available to our colleagues. And no more password forms.

API Credentials

The first step in using Google to manage your identities for your Django project is getting API credentials from Google:

  1. Sign into your Google Apps account in your browser
  2. Visit https://code.google.com/apis/console#access in the same browser
  3. On the left menu, Create a new Project
  4. To start, you don’t need any Services, so select the API Access tab rom the left menu and “Create an OAuth 2.0 client ID…”
  5. Fill out the Client ID form for a “web application” and use localhost:8000 as your hostname

Now that you have API Access, you need to Edit settings for the new “Client ID for web applications” you just created. Specifically, you need to enter new “Authorized Redirect URIs” (one per line):

http://localhost:8000/complete/google-oauth2/
http://{dev server}/complete/google-oauth2/
https://{prod server}/complete/google-oauth2/

These are the URLs that Google will return the user to after they have authenticated. Omit the dev server and prod server if you don’t yet know them.

Next, we’ll use those credentials to setup the django-social-auth package, so keep this page open.

Using django-social-auth

django-social-auth is a great package for getting started quickly, in part because it supports a wide range of services out of the box and also because it has detailed documentation.

After you’ve installed the django-social-auth package inside your virtualenv, you need to follow the basic configuration instructions for your Django project. In your settings.py, make sure 'social_auth' is in the INSTALLED_APPS and then run ./manage.py syncdb to get the new tables that django-social-auth requires.

You will also need to add a few more things to settings.py:

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Django Social Auth Config

AUTHENTICATION_BACKENDS = ( 
    'social_auth.backends.google.GoogleOAuth2Backend',  # putting this 1st means that most users will auth with their Google identity
    'django.contrib.auth.backends.ModelBackend',        # ...but this one means we can still have local admin accounts as a fallback
)

LOGIN_URL          = '/login/google-oauth2/'       
LOGIN_ERROR_URL    = '/login-error/'

SOCIAL_AUTH_RAISE_EXCEPTIONS = False
SOCIAL_AUTH_PROCESS_EXCEPTIONS = 'social_auth.utils.log_exceptions_to_messages'  # ...assuming you like the messages framework

GOOGLE_OAUTH2_CLIENT_ID      = 'yourCLIENTidHERE'  # this is on the credentials web page from above
GOOGLE_OAUTH2_CLIENT_SECRET  = 'YOURsecretHERE'    # this is also on the credentials web page from above
GOOGLE_WHITE_LISTED_DOMAINS = ['your-domain.com']  # this is what actually limits access

SOCIAL_AUTH_COMPLETE_URL_NAME  = 'socialauth_complete'
SOCIAL_AUTH_ASSOCIATE_URL_NAME = 'socialauth_associate_complete'

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The most important line from the above is the GOOGLE_WHITE_LISTED_DOMAINS. It’s this setting that limits access to users inside your organization.

Views and URLs

Now that we’ve got auth from Google, we need to wire it up. For a normal application, you’ll want to create a typical view and template for logging in, errors while logging in, a logout view (to delete your cookies), and then ensure you are using the login_required decorator or other access control. For this blog post, I’ll just sketch these out, based mainly off your main urls.py:

...
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import logout
from django.views.generic import TemplateView
...

urlpatterns += patterns('', 
    url(r'', include('social_auth.urls')),                                          # we absolutely need these ones

    url(r'^$', TemplateView.as_view(template_name="login.html")),                   # also fairly important
    url(r'^logout/$', logout, {'next_page': '/'}, name='gauth_logout'),             # this one is nice, but not totally required

    url(r'^login-error/$', TemplateView.as_view(template_name="login-error.html")), # if you've set up messages, you could loop through them here

    # Now we can test whether this stuff works
    url(r'^secrets$', login_required(TemplateView.as_view(template_name="secrets.html"))),  

)

If we set this up and then create a secrets.html in our templates directory:

THIS IS A SECRET!

… and a login.html in our templates directory:

<p>Use your work email credentials to sign in to this application: 
  <a href="{% url socialauth_begin 'google-oauth2' %}?next=/secrets">Sign In</a>
</p>

At this point, you should be able to start the Django debug server with ./manage.py runserver.

Trying it out

If you visit http://localhost:8000/secrets with your browser now, you should be able to try it out. First off, you should not see your secrets yet (even if you are logged in). Before you get there, you need to both be logged into a Google account and grant access to let Google give your identity to this new application. After that happens, Google and django-social-auth will double-check that you are legit and pass the GOOGLE_WHITE_LISTED_DOMAINS. Finally, Google will send you back to the application and in this case you will be redirected to your ?next param.

Do also try it with a personal GMail account to make sure it errors with the login-error.html template. That’s the GOOGLE_WHITE_LISTED_DOMAINS at work.

Gotchas

Well, the most obvious failure is that you use a browser that is logged into your personal GMail rather than your Google Apps for work. The less obvious failure is that this will only work locally if you are running the Django debug server on port 8000 and putting localhost:8000 into your browser (127.0.0.1 won’t work).

It’s probably also worth adding this to one of your loggers inside your LOGGING:

        'SocialAuth': {
            'handlers':['console'],
            'propagate': True,
            'level':'DEBUG',
        }

One thought on “Google Apps Auth for Internal Django Sites

  1. Pingback: Eight Great Tools Simple Enough for a CEO | Digital publishing and technology posts from the team at Safari Books Online

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s