• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

contrib/opal/ZSI/build/lib/ZSI/digest_auth.py

00001 #! /usr/bin/env python
00002 # $Header$
00003 '''Utilities for HTTP Digest Authentication
00004 '''
00005 import re
00006 from md5 import md5
00007 import random
00008 import time
00009 import httplib
00010 
00011 random.seed(int(time.time()*10))
00012 
00013 def H(val):
00014   return md5(val).hexdigest()
00015 
00016 def KD(secret,data):
00017   return H('%s:%s' % (secret,data))
00018 
00019 def A1(username,realm,passwd,nonce=None,cnonce=None):
00020   if nonce and cnonce:
00021     return '%s:%s:%s:%s:%s' % (username,realm,passwd,nonce,cnonce)
00022   else:
00023     return '%s:%s:%s' % (username,realm,passwd)
00024 
00025 def A2(method,uri):
00026   return '%s:%s' % (method,uri)
00027 
00028 def dict_fetch(d,k,defval=None):
00029   if d.has_key(k):
00030     return d[k]
00031   return defval
00032 
00033 def generate_response(chaldict,uri,username,passwd,method='GET',cnonce=None):
00034   """
00035   Generate an authorization response dictionary. chaldict should contain the digest
00036   challenge in dict form. Use fetch_challenge to create a chaldict from a HTTPResponse
00037   object like this: fetch_challenge(res.getheaders()).
00038 
00039   returns dict (the authdict)
00040 
00041   Note. Use build_authorization_arg() to turn an authdict into the final Authorization
00042   header value.
00043   """
00044   authdict = {} 
00045   qop = dict_fetch(chaldict,'qop')
00046   domain = dict_fetch(chaldict,'domain')
00047   nonce = dict_fetch(chaldict,'nonce')
00048   stale = dict_fetch(chaldict,'stale')
00049   algorithm = dict_fetch(chaldict,'algorithm','MD5')
00050   realm = dict_fetch(chaldict,'realm','MD5')
00051   opaque = dict_fetch(chaldict,'opaque')
00052   nc = "00000001"
00053   if not cnonce:
00054     cnonce = H(str(random.randint(0,10000000)))[:16]
00055 
00056   if algorithm.lower()=='md5-sess':
00057     a1 = A1(username,realm,passwd,nonce,cnonce)
00058   else:
00059     a1 = A1(username,realm,passwd)
00060 
00061   a2 = A2(method,uri)
00062 
00063   secret = H(a1)
00064   data = '%s:%s:%s:%s:%s' % (nonce,nc,cnonce,qop,H(a2))
00065   authdict['username'] = '"%s"' % username
00066   authdict['realm'] = '"%s"' % realm
00067   authdict['nonce'] = '"%s"' % nonce
00068   authdict['uri'] = '"%s"' % uri
00069   authdict['response'] = '"%s"' % KD(secret,data)
00070   authdict['qop'] = '"%s"' % qop
00071   authdict['nc'] = nc
00072   authdict['cnonce'] = '"%s"' % cnonce
00073   
00074   return authdict
00075 
00076 
00077 def fetch_challenge(http_header):
00078   """ apparently keywords Basic and Digest are not being checked 
00079   anywhere and decisions are being made based on authorization 
00080   configuration of client, so I guess you better know what you are
00081   doing.  Here I am requiring one or the other be specified.
00082 
00083       challenge Basic auth_param
00084       challenge Digest auth_param
00085   """
00086   m = fetch_challenge.wwwauth_header_re.match(http_header)
00087   if m is None:
00088       raise RuntimeError, 'expecting "WWW-Authenticate header [Basic,Digest]"'
00089 
00090   d = dict(challenge=m.groups()[0])
00091   m = fetch_challenge.auth_param_re.search(http_header)
00092   while m is not None:
00093       k,v = http_header[m.start():m.end()].split('=')
00094       d[k.lower()] = v[1:-1]
00095       m = fetch_challenge.auth_param_re.search(http_header, m.end())
00096        
00097   return d
00098 
00099 fetch_challenge.wwwauth_header_re = re.compile(r'\s*([bB]asic|[dD]igest)\s+(?:[\w]+="[^"]+",?\s*)?')
00100 fetch_challenge.auth_param_re = re.compile(r'[\w]+="[^"]+"')
00101 
00102 
00103 def build_authorization_arg(authdict):
00104   """
00105   Create an "Authorization" header value from an authdict (created by generate_response()).
00106   """
00107   vallist = []
00108   for k in authdict.keys():
00109     vallist += ['%s=%s' % (k,authdict[k])]
00110   return 'Digest '+', '.join(vallist)
00111 
00112 if __name__ == '__main__': print _copyright

Generated on Wed Oct 20 2010 11:12:15 for APBS by  doxygen 1.7.2