Archive for September 18th, 2008
Authenticating in GAE
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.
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.
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 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.
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