Technorati Tags: 
asp.net,
python,
cgi  
I recently had my first shot at writing cgi scripts in python. It was an altogether different experience having come from a .Net and Turbogears background. I also got my hands on a Linux server. Infact, it was the first time I got to use vi, ls, cat, cp etc, since college. It is really amazing how much you can do with just the shell commands on Linux. 
  
  
The Linux machine had an apache server which ran some cgi scripts to do some basic tasks like creating a new user record in the database, deleting, editing etc. I think that was the reason they did not go beyond cgi. These tasks were manually done by an admin after logging into the application. Now, these scripts were required to be made callable from an asp.net web application.
  
  
ASP.NET application <===========> Python cgi scripts    
CreateDemo.aspx _____________ create_demo.cgi    
(collects user info    
for demo record) _____________ (requires authentication)    
  
So, we decided to create another script, let us say 'authenticate.cgi', in which we used urllib python library to by pass the authentication on create_demo.cgi and then CreateDemo.aspx would call authenticate.cgi. Here is the new flow-    
  
CreateDemo.aspx --> authenticate.cgi --> create_demo.cgi    
  
This write-up addresses two key areas:    
1. How to communicate with a python cgi script from an asp.net web page?
  
//Request url and request method     
 
  
  
HttpWebRequest httpRequest = HttpWebRequest)WebRequest.Create("http://192.1.1.1/no_auth/authenticate.cgi?name=harpreet”);     
 
  
  
httpRequest.KeepAlive = false;     
 
  
  
httpRequest.Method = "GET";     
 
  
  
//Read the web response from the URI     
 
  
  
string strResponse = string.Empty;     
 
  
  
using (WebResponse webResponse = (WebResponse)httpRequest.GetResponse()) 
  
{
  
          System.Text.Encoding enc = System.Text.Encoding.GetEncoding(1252);     
 
  
  
          using (StreamReader srResponseStream = new StreamReader(webResponse.GetResponseStream(), enc))     
 
  
  
          {     
 
  
  
                //Read the response into a string or you could use XML also     
 
  
  
                strResponse = srResponseStream.ReadToEnd();     
 
  
  
           }     
 
  
  
}    
  
2. How to by pass basic authentication on cgi script using urllib?
  
#!/usr/bin/env /usr/local/bin/python     
 
  
  
import urllib2,urllib
  
import sys,os,cgi,cgitb     
 
  
  
import re,datetime     
 
  
  
import base64     
 
  
  
from urlparse import urlparse     
 
  
  
def handler():     
 
  
  
  form = cgi.FieldStorage()     
 
  
  
  if form.list:     
 
  
  
  data = {}     
 
  
  
  for field in flds:     
 
  
  
   data[field]=form.getvalue(field,'')     
 
  
  
  theurl = 'http://localhost/admin/create_demo.cgi’          
  
  
  # you'll need to supply a protected page with your username and password          
  
  
  username = 'scott'          
  
  
  password = 'tiger' # a very bad password     
 
  
  
  req = urllib2.Request(theurl)     
 
  
  
  try:     
 
  
  
     handle = urllib2.urlopen(req, urllib.urlencode(data))     
 
  
  
  except IOError, e:
  
  # do whatever you want to handle the exception here, 'pass' in this example          
  
  
    pass          
  
  
  else:
  
    # If we don't fail then the page isn't protected          
  
  
    print "This page is not protected by any authentication."          
  
  
    sys.exit(1)     
 
  
  
  if not hasattr(e, 'code') or e.code != 401:     
 
  
  
    # we got an error - but not a 401 error          
  
  
    print "This page is not protected by any authentication."          
  
  
    print 'Some other reason for failure'          
  
  
    sys.exit(1)     
 
  
  
  authheader = e.headers['www-authenticate']     
 
  
  
    
 
  
  
  # this gets the www-authenticate line from the headers          
  
  
  # which would contain the authentication scheme and realm          
  
  
  authobj = re.compile(r'''(?:\s*www-authenticate\s*:)?\s*(\w*)\s+realm=['"]([^'"]+)['"]''',re.IGNORECASE)     
 
  
  
  # this RE is used to extract scheme and realm     
 
  
  
  matchobj = authobj.match(authheader)     
 
  
  
  # if the authheader isn't matched by the regular expression          
  
  
  # then there is probably some error in the header          
  
  
  if not matchobj:     
 
  
  
    print 'The authentication header is badly formed.'          
  
  
    print authheader 
  
    
 
  
  
    sys.exit(1)     
 
  
  
  scheme = matchobj.group(1)     
 
  
  
  realm = matchobj.group(2)     
 
  
  
  # check schem (this example works for basic authorization only          
  
  
  if scheme.lower() != 'basic':     
 
  
  
    print 'This example only works for BASIC Authorization.'          
  
  
    sys.exit(1)     
 
  
  
  base64string = base64.encodestring('%s:%s' % (username, password))[:-1]     
 
  
  
  authheader = "Basic %s" % base64string     
 
  
  
  req.add_header("Authorization", authheader)     
 
  
  
    
 
  
  
  try:     
 
  
  
    handle = urllib2.urlopen(req,urllib.urlencode(data))     
 
  
  
  except IOError, e:     
 
  
  
    print "The username or password is not valid."          
  
  
    sys.exit(1)     
 
  
  
  thepage = handle.read()     
 
  
  
    
 
  
  
  print "Content-type: text/html; charset=utf-8"          
  
  
  print          
  
  
  print thepage
  
handler()     
 
  
  
  
Security was not really a major concern for this cgi, but an IP based security was added to limit unwanted access.
  
* The code snippets are not really tested but, will hopefully work :-)