From: <bov...@us...> - 2007-01-25 23:09:16
|
Revision: 1336 http://svn.sourceforge.net/pywebsvcs/?rev=1336&view=rev Author: boverhof Date: 2007-01-25 15:09:17 -0800 (Thu, 25 Jan 2007) Log Message: ----------- A test/test_rfc2617.py M test/test_zsi.py M test/test_zsi_net.py M test/wsdl2py/test_AWSECommerceService.py M ZSI/digest_auth.py M ZSI/client.py -- merge over changes Report [ 1593310 ] Http Digest authentication fails Modification of Patch [ 1593314 ] HttpDigest authentication patch Modified Paths: -------------- trunk/zsi/ZSI/client.py trunk/zsi/ZSI/digest_auth.py trunk/zsi/test/test_zsi.py trunk/zsi/test/test_zsi_net.py trunk/zsi/test/wsdl2py/test_AWSECommerceService.py Added Paths: ----------- trunk/zsi/test/test_rfc2617.py Modified: trunk/zsi/ZSI/client.py =================================================================== --- trunk/zsi/ZSI/client.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/ZSI/client.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -277,9 +277,9 @@ print >>self.trace, "_" * 33, time.ctime(time.time()), "REQUEST:" print >>self.trace, soapdata - #scheme,netloc,path,nil,nil,nil = urlparse.urlparse(url) - path = _get_postvalue_from_absoluteURI(url) - self.h.putrequest("POST", path) + url = url or self.url + request_uri = _get_postvalue_from_absoluteURI(url) + self.h.putrequest("POST", request_uri) self.h.putheader("Content-Length", "%d" % len(soapdata)) self.h.putheader("Content-Type", 'text/xml; charset=utf-8') self.__addcookies() @@ -296,7 +296,7 @@ elif self.auth_style == AUTH.httpdigest and not headers.has_key('Authorization') \ and not headers.has_key('Expect'): def digest_auth_cb(response): - self.SendSOAPDataHTTPDigestAuth(response, soapdata, url, soapaction, **kw) + self.SendSOAPDataHTTPDigestAuth(response, soapdata, url, request_uri, soapaction, **kw) self.http_callbacks[401] = None self.http_callbacks[401] = digest_auth_cb @@ -308,7 +308,7 @@ # Clear prior receive state. self.data, self.ps = None, None - def SendSOAPDataHTTPDigestAuth(self, response, soapdata, url, soapaction, **kw): + def SendSOAPDataHTTPDigestAuth(self, response, soapdata, url, request_uri, soapaction, **kw): '''Resend the initial request w/http digest authorization headers. The SOAP server has requested authorization. Fetch the challenge, generate the authdict for building a response. @@ -333,7 +333,7 @@ dict_fetch(chaldict,'realm',None) and \ dict_fetch(chaldict,'qop',None): authdict = generate_response(chaldict, - url, self.auth_user, self.auth_pass, method='POST') + request_uri, self.auth_user, self.auth_pass, method='POST') headers = {\ 'Authorization':build_authorization_arg(authdict), 'Expect':'100-continue', Modified: trunk/zsi/ZSI/digest_auth.py =================================================================== --- trunk/zsi/ZSI/digest_auth.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/ZSI/digest_auth.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -2,7 +2,7 @@ # $Header$ '''Utilities for HTTP Digest Authentication ''' - +import re from md5 import md5 import random import time @@ -75,24 +75,31 @@ def fetch_challenge(http_header): + """ apparently keywords Basic and Digest are not being checked + anywhere and decisions are being made based on authorization + configuration of client, so I guess you better know what you are + doing. Here I am requiring one or the other be specified. + + challenge Basic auth_param + challenge Digest auth_param """ - Create a challenge dictionary from a HTTPResponse objects getheaders() method. - """ - chaldict = {} - vals = http_header.split(' ') - chaldict['challenge'] = vals[0] - for val in vals[1:]: - try: - a,b = val.split('=') - b=b.replace('"','') - b=b.replace("'",'') - b=b.replace(",",'') - chaldict[a.lower()] = b - except: - pass - return chaldict + m = fetch_challenge.wwwauth_header_re.match(http_header) + if m is None: + raise RuntimeError, 'expecting "WWW-Authenticate header [Basic,Digest]"' + d = dict(challenge=m.groups()[0]) + m = fetch_challenge.auth_param_re.search(http_header) + while m is not None: + k,v = http_header[m.start():m.end()].split('=') + d[k.lower()] = v[1:-1] + m = fetch_challenge.auth_param_re.search(http_header, m.end()) + + return d +fetch_challenge.wwwauth_header_re = re.compile(r'\s*([bB]asic|[dD]igest)\s+(?:[\w]+="[^"]+",?\s*)?') +fetch_challenge.auth_param_re = re.compile(r'[\w]+="[^"]+"') + + def build_authorization_arg(authdict): """ Create an "Authorization" header value from an authdict (created by generate_response()). Added: trunk/zsi/test/test_rfc2617.py =================================================================== --- trunk/zsi/test/test_rfc2617.py (rev 0) +++ trunk/zsi/test/test_rfc2617.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -0,0 +1,52 @@ +#!/usr/bin/env python +""" +RFC2617 + +HTTP Authentication: Basic and Digest Access Authentication +""" +import unittest +from ZSI import digest_auth +from ZSI.wstools.logging import setBasicLoggerDEBUG +setBasicLoggerDEBUG() + +class DATestCase(unittest.TestCase): + "test Union TypeCode" + + def check_challenge_single_www_authenticate_header(self): + challenge='Basic realm="WallyWorld"' + print "=="*30 + print challenge + print "=="*30 + cd = digest_auth.fetch_challenge(challenge) + expect = {'challenge': 'Basic', 'realm': 'WallyWorld'} + self.failUnless(cd == expect, 'Expected equivalent') + + def check_challenge_single_www_authenticate_header2(self): + challenge='Basic realm="Wally World"' + cd = digest_auth.fetch_challenge(challenge) + expect = {'challenge': 'Basic', 'realm': 'Wally World'} + self.failUnless(cd == expect, 'Expected equivalent') + + def check_challenge_single_www_authenticate_header3(self): + challenge = '''Digest + realm="tes...@ho...", + qop="auth,auth-int", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + opaque="5ccc069c403ebaf9f0171e9517f40e41"''' + cd = digest_auth.fetch_challenge(challenge) + expect = {'nonce': 'dcd98b7102dd2f0e8b11d0f600bfb0c093', 'challenge': 'Digest', 'opaque': '5ccc069c403ebaf9f0171e9517f40e41', 'realm': 'tes...@ho...', 'qop': 'auth,auth-int'} + self.failUnless(cd == expect, 'Expected equivalent') + + + +def makeTestSuite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(DATestCase, "check")) + return suite + +def main(): + unittest.main(defaultTest="makeTestSuite") + +if __name__ == '__main__': + main() + Modified: trunk/zsi/test/test_zsi.py =================================================================== --- trunk/zsi/test/test_zsi.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/test/test_zsi.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -11,6 +11,7 @@ import test_union import test_list import test_TCtimes +import test_rfc2617 def makeTestSuite(): return unittest.TestSuite( Modified: trunk/zsi/test/test_zsi_net.py =================================================================== --- trunk/zsi/test/test_zsi_net.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/test/test_zsi_net.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -12,6 +12,7 @@ import test_union import test_TCtimes import test_list +import test_rfc2617 def makeTestSuite(): return unittest.TestSuite( Modified: trunk/zsi/test/wsdl2py/test_AWSECommerceService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -47,9 +47,9 @@ """Test case for Amazon ECommerce Web service """ name = "test_AWSECommerceService" - client_file_name = "AWSECommerceService_services.py" - types_file_name = "AWSECommerceService_services_types.py" - server_file_name = "AWSECommerceService_services_server.py" + client_file_name = "AWSECommerceService_client.py" + types_file_name = "AWSECommerceService_types.py" + server_file_name = "AWSECommerceService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) @@ -96,7 +96,7 @@ def test_net_ItemSearch(self): loc = self.client_module.AWSECommerceServiceLocator() - port = loc.getAWSECommerceServicePortType(**self.getPortKWArgs()) + port = loc.getAWSECommerceServicePort(**self.getPortKWArgs()) msg = self.client_module.ItemSearchRequestMsg() msg.SubscriptionId = '0HP1WHME000749APYWR2' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |