When writing an application, it is always handy when your platform of choice offers some sort of plug and play authentication mechanism. For example, ASP.NET has authentication providers that allow users to authenticate against Windows accounts or against username/password combinations in a data store. For Internet based applications, there has been a large push to separate authentication from authorization. The reason for this is simple: users want to use a large number of applications and need to be authenticated for each application. Each of these applications has a choice to make: use a custom username/password that only it knows about or trust a third party to provide an identity. Many web sites choose to implement their own username/password list. Over time, this simply means that people tend to use the same username/password combination on all sites that they access. The downside here is that if one site is compromised, the attacker has probably gained access to many identity on several more popular sites. A site like EBay or Amazon probably won’t be compromised. But, a less popular site with only a few dozen or few hundred users, written by a hobbyist, may be easily compromised. If just one or two users have an active account at a site like Amazon, those users might find themselves holding a lot of debt.
To work around this issue, Microsoft released a product originally called Passport, today known as Windows Live ID. It’s original goal was to allow for a way for Microsoft to vouch for someone’s identity independent of the rights of that identity. Believe it or not, Microsoft was ahead of its time when creating this authentication mechanism. After learning a number of lessons about how to set up identity providers and parties that rely on those parties, the industry came together and created OpenID. If you are really interested in how OpenID works, I encourage you to spend some quality time on the OpenID web site. So, what do we need to know? OpenID put together specifications that state how the authenticators, known as OpenID Providers (OPs), work with Relying Parties (RPs). RPs typically have a fixed set of OPs that they will use for authentication. The RP has to trust the identities provided to it by the OP– an OP that verifies or refutes every claimed identity is easy to write and of no value in verifying someone’s identity.
The long story about OpenID is important– when building a larger web site, you want to use OpenID in your finished site. It allows you to broaden your appeal by letting someone use an established identity. That said, you need to start with something. Having to do minimal work to get delegated authentication up and running sounds good. You can start out by choosing to trust Google identities. App Engine makes this all incredibly easy.
You start out by importing the users types:
from google.appengine.api import users
From here, it is a simple one liner to get the current user:
currentUser = users.get_current_user()
If currentUser is set to None, we know that no one has logged in using Google authentication. If the return value is not None, we can get information about the user, such as their nickname and e-mail address. We can use this information to personalize the page a bit for each user. The get handler for the main page (which inherits from webapp.RequestHandler) does this with the following code:
1 def get(self):
2 loggedIn = False
3 username = "test"
4 currentUser = users.get_current_user()
5 if currentUser:
6 url = users.create_logout_url(self.request.uri)
7 url_linktext = ‘Logout’
8 loggedIn = True
9 username = currentUser.nickname().strip()
10 if (len(username) < 1):
11 username = currentUser.email().strip()
12 else:
13 url = users.create_login_url(self.request.uri)
14 url_linktext = ‘Login’
15
16 template_values = {
17 ‘url’: url,
18 ‘url_linktext’: url_linktext,
19 ‘loggedIn’: loggedIn,
20 ‘username’: username,
21 }
22
23 path = os.path.join(os.path.dirname(__file__), ‘Pages/index.html’)
24 self.response.out.write(template.render(path, template_values))
The users class contains two helper meth
ods to create login and logout URLs. The rest of this information is passed to our Django template for display on the page:
1 <div id="Columns">
2 <div id="LeftColumn">
3 <a href="{{url}}">{{url_linktext}}</a>
4 </div>
5 <div id="RightColumn">
6 {% if loggedIn %}
7 Hello, {{username}}!
8 {% else %}
9 Please log in.
10 {% endif %}
11 </div>
12 </div>