finally{}

all will be well finally

Archive for September 18th, 2008

Authenticating in GAE

with 5 comments

Having successfully created a desktop application in IronPython, I wanted to go a step further – integrate desktop and web environment. Data can be captured in desktop and passed on to web; and analysis can be done on the web.

To start with it, I need to authenticate the incoming request. Hmm…when I started reading about authentication I read so many jargons that scared me – openid, openauth, authsub, basicauth. It took me a while to understand the basics of each (still I don’t claim that I’ve understood them; probably whatever I’ve understood is wrong too)

To some extent, I understood ‘Basic Authentication’ and this is how I went about implementing it.

image

First of all, I am going with Google Account Authentication, assuming all the users will have a Google account; getting one is not a big deal.

IronPython Desktop Application will pass userid, password to AppEngine Application, which in turn will validate with Google Accounts Authentication service. If authenticated, AppEngine application will proceed; else it will pass the error back to the desktop application.

Having discussed the concepts, here are the code snippets. I’m sharing with a hope that it will be useful to someone; or if this is wrong, someone will raise an alarm; or if there is a better way to do it, someone will comment.

AppEngine

Here the expectation is that the incoming request will have a header (‘HTTP_AUTHORIZATION’) with userid and password in Base64 format.

from google.appengine.api import users
import urllib
import base64
from google.appengine.api import urlfetch
from django.http import HttpResponse

def authenticate(request):
  response_vals={}
  resp = HttpResponse()
  try:
    (method, encoded) = request.META['HTTP_AUTHORIZATION'].split()
    response_vals['method'] = method
    response_vals['encoded'] = encoded
    if method.lower() == 'basic':
        (username, password) = base64.b64decode(encoded).split(':')

        request_body = urllib.urlencode({'Email': username,
                                         'Passwd': password,
                                         'accountType': 'HOSTED_OR_GOOGLE',
                                         'service': 'ah',
                                         'source': 'test'})
        auth_response = urlfetch.fetch('https://www.google.com/accounts/ClientLogin',
                                       method=urlfetch.POST,
                                       headers={'Content-type':'application/x-www-form-urlencoded',
                                                'Content-Length':
                                                 str(len(request_body))},
                                       payload=request_body)
        resp.status_code = auth_response.status_code
  except:
    resp.status_code = 401
    return resp
  return resp
Desktop – Python

Encode the user id, password and call the particular URL (/auth?). And handle the response.

import urllib
import urllib2
import base64

url = 'http://localhost:8000/api/auth/'
username = 'mysecs@gmail.com'
password = 'mysecspwd'
USER_AGENT = 'mySecsWndClient'

request = urllib2.Request(url)
base64string = base64.encodestring('%s:%s' % (username,password))
authheader =  "Basic %s" % base64string
request.add_header('USER_AGENT', USER_AGENT)
request.add_header('AUTHORIZATION', authheader)

try:
  response = urllib2.urlopen(request).read()
  print response
except urllib2.HTTPError, e:
  print e.code
  print e.read()
except urllib2.URLError, e:
   if hasattr(e, 'reason'):
    print e.reason
   elif hasattr(e,'code'):
    print e.code
Desktop – IronPython

Since I’ve written mySecs in IronPython, I’ve to translate the above into IronPython. As ipy is a relatively new entrant, there is not much of documentation on how to do it. Here is what I’ve done.

import System
from System.IO import StreamReader
from System.Net import HttpWebRequest, NetworkCredential, WebException

url = 'http://localhost:8000/api/auth/'
username = 'mysecs@gmail.com'
password = 'mysecspwd'
USER_AGENT = 'mySecsWndClient'


req = HttpWebRequest.Create(url)
req.UserAgent = USER_AGENT
auth_string = '%s:%s' % (username,password)
authheader =  "Basic %s" % System.Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(auth_string))
req.Headers.Add('AUTHORIZATION', authheader)

try:
    rsp = req.GetResponse()
    response = StreamReader(rsp.GetResponseStream()).ReadToEnd()
    print response
    rsp.Close()
except (Exception, WebException), e:
    print 'Error: %s' % e

Applies to: GAE 1.1.1; Django 0.96 with helper; IronPython 1.1

Reference:

AuthSub Authentication for Web Applications

Basic Authentication – Authentication with Python

Written by Joseph Jude

September 18th, 2008 at 1:07 pm

Posted in Programming

Tagged with