Personafied

Published September 5, 2013. Filed under: Django, Meta, Python.

Reminder for people who try and think it’s a bug: Persona, on this site, is for me to be able to log in and post entries. As such, you will not be able to log in to this site, since you don’t have an account and can’t create one. This isn’t a bug, it’s intended functionality — site owners can control whether accounts can be created, and by whom.

So, last week I mentioned in passing that my next project for this site would be implementing Persona for authentication. Since I work at Mozilla, I’ve had some exposure to it already in real projects — on MDN we switched to Persona a while back, when it was still being called “BrowserID” — and, though I have a long history of being skeptical of federated-identity and single-sign-on systems, Persona has finally changed my mind.

Also, as of a couple days ago, Persona is the sole authentication system for this site. I’ll get to how that was accomplished in a bit, but since Persona is still a pretty new thing I figured I’d take a moment, first, to explain just what Persona is, and why it won me over in the end.

Now, you may have already seen some basic explanations of Persona. For the most part they tend to focus on the end-user benefits, specifically:

That last one is a big deal, in this age of password breaches, since it means you don’t have to make up a bunch of passwords for different sites, and you don’t have to trust a bunch of sites to safely store passwords. When you get right down to it, Persona doesn’t actually require any passwords. But to see why, we need to actually look at what goes on.

And a quick note here: in a few places I’ll mention things happening in the browser; that can mean the browser has native support (being worked on for Firefox on all its various platforms), or that JavaScript running in the browser is providing the support. Regardless of which way it’s implemented, the protocol is the same, though.

How it works

With as little spec language as possible (you can read the full documentation over at MDN if you really want that), here’s what Persona actually does: it’s a simple, usable, implemented-in-the-browser application of public-key cryptography. No, really.

Persona starts with you, the user. You have at least one email address; you can have more if you want, and use each one as a separate identity. For each email address you’re using, you’ll have an identity provider, which is just someone who’s willing to vouch for the fact that you are someone who controls that email address. Your identity provider can be you (if you manage your own email and want to run your own provider), or it can be your email provider, or it can be Mozilla’s fallback provider at persona.org, which confirms that you control an email address by sending a verification message to that address.

Your browser will generate a public/private keypair for each email address. These can be somewhat transient, and each browser you use will generate its own keypairs for each address. Authenticating with your identity provider can be handled basically any way that the two of you can agree on: you can do password authentication, two-factor auth, or really just about anything, so long as your browser sends the provider a copy of the public key it’s generated for that email address. What you get back from this process is a Persona certificate — a JavaScript object containing:

When you sign into a site with Persona, your browser will (assuming it has a certificate already; if not, it’ll get one from your identity provider) generate what Persona calls the “assertion”: a JavaScript object, containing the email address you’re signing in with and the site you’re trying to sign into, signed with the private key for that email address. Your browser sends the assertion and the certificate to the site, which then just walks through verifying that:

  1. This is in fact the site you’re trying to sign in to.
  2. The certificate issuer’s domain matches the email address domain, or is login.persona.org.
  3. The certificate hasn’t expired.
  4. The public key contained in the certificate verifies the signature on the assertion.
  5. The identity provider’s public key (there’s a protocol for fetching that) verifies the signature on the certificate.

If those checks pass, you’re signed in. From there, you might just do stuff that’s identified with your email address, you might create a more detailed profile if you like (and if the site offers that), etc. etc.

Why it’s cool

First of all, yes, unlike OpenID this is based on something most people on the Web already have: an email address. That’s a big win right off the bat. More importantly, the way Persona is constructed means that it offers some very interesting options for user privacy. For example, your identity provider does not necessarily know what sites you’re signing into, because the only thing they see from the site is a request for their public key. All they know is that someone for whom they’re the provider is signing in, and it should be relatively easy to set things up such that it’s not possible to match that event up to a specific user through traffic analysis (i.e., a request from this user for a certificate, immediately followed by a request from a site for the public key).

That stuff is a ways down the road, though, since there are very few identity providers right now, and most sites that implement Persona aren’t actually doing verification on their own servers; they’re doing it through Mozilla’s remote-verficiation API at persona.org (meaning, if Mozilla is your provider, and the site you’re signing into just uses the remote API to verify you, then Mozilla can see that it’s you signing in to the site — the verification API basically just lets sites post over the certificate and assertion, and get back a response indicating whether the checks pass).

Also of interest is how wide-open the process of authenticating with your identity provider is; for example, when I use my @mozilla.com email address, I’m authenticated through Mozilla’s LDAP system. The persona.org service also has bridges which take advantage of existing authentication systems used by email providers. The first rollout supported Yahoo email, and now Gmail is supported as well. And that’s really just the start; while it would be awesome to have lots of proper identity providers running around, it’s also possible to support a ton of people, through their email providers, via these kinds of bridges.

How I set it up

The easy way to get Persona auth in Django is with django-browserid, which does offload to the persona.org verifier rather than doing verification on its own (there’s been talk of integrating PyBrowserID support, since it implements a local verifier), so there’s a minimum of crypto libraries needed (in fact, none). The name, as mentioned earlier, is from the very early days when Persona was still internally referred to as “BrowserID”.

As it turns out, django-browserid has some pretty good documentation, and is almost stupidly easy to work with. I had to put in a bit of extra effort since Python 3 support is being worked on (hence I’m deploying off a fork where I’ve cleaned that up), but since all the Django-y bits of my site are in a public repository you can see the commit that added Persona, and it really is not much code at all. The only thing I needed beyond that was to add the following in my local settings on the server:

SITE_URL = 'http://www.b-list.org'
LOGIN_REDIRECT_URL = '/'
BROWSERID_CREATE_USER = False

The SITE_URL setting is required for Persona to work, and has to match where your site is running. And BROWSERID_CREATE_USER lets you enable or disable automatic creation of new accounts for email address which don’t match any existing User in your database; since I’m the only user here, and already have a User matching my email address, I want that turned off.

I also popped open a Python interpreter, fetched my Django User instance, and called its set_unusable_password() method, since I’m never going to use a password on it ever again.

And… that’s it. Really. Everything Just Works™, including sign in, sign out, the admin, everything. It really was almost stupidly easy, which is the way authentication should be.