Changeset 4038 for TI12-security


Ignore:
Timestamp:
10/07/08 15:45:22 (11 years ago)
Author:
pjkersha
Message:

Completed ElementTree - ZSI integration for WS-Security SignatureHandler? but still problems with ET C14N for signature generation: C14N produces superfluous xmlns declarations.

Location:
TI12-security/trunk/python
Files:
7 edited
1 moved

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/Tests/etreewss/client/echoClientTest.py

    r4024 r4038  
    1313 
    1414from ConfigParser import SafeConfigParser 
    15 from ndg.security.common.wssecurity.etree import SignatureHandler 
     15from ndg.security.common.wssecurity.etree import SignatureHandler, \ 
     16                                                NoSignatureFound 
    1617 
    1718from os.path import expandvars as xpdVars 
     
    1920mkPath = lambda file: jnPath(os.environ['NDGSEC_WSSECLNT_UNITTEST_DIR'], file) 
    2021 
    21 from elementtreeproxy import ElementTreeProxy 
     22from ndg.security.common.zsi_utils.elementtreeproxy import ElementTreeProxy 
    2223 
     24import logging 
     25logging.basicConfig(level=logging.DEBUG) 
     26log = logging.getLogger(__name__) 
    2327 
    2428class EchoClientTestCase(unittest.TestCase): 
     
    4852         
    4953        # Signature handler object is passed to binding 
     54        # TODO: swap 'unsupressedPrefixes' to 'inclusive_namespaces' in 
     55        # wssecurity.WSSecurityConfig 
    5056        sigHandler = SignatureHandler( 
    5157                                 signingPriKeyFilePath=signingPriKeyFilePath, 
     
    5359                                 signingCertFilePath=signingCertFilePath, 
    5460                                 caCertFilePathList=caCertFilePathList, 
    55                                  refC14nKw={'unsuppressedPrefixes':[]}, 
    56                                  signedInfoC14nKw={'unsuppressedPrefixes':[]}) 
     61                                 refC14nKw={'inclusive_namespaces':[]}, 
     62                                 signedInfoC14nKw={'inclusive_namespaces':[]}) 
    5763 
    5864        locator = EchoServiceLocator() 
     
    6773        '''test1Echo: test signed message and signed response from server''' 
    6874             
    69         try: 
     75        try:   
    7076            resp = self.clnt.Echo("Hello from client") 
    71             print "Message returned was: %s" % resp 
     77            log.info("Message returned was: %s", resp) 
     78        except NoSignatureFound: 
     79            log.info("No signature in response") 
    7280        except: 
    7381            self.fail(traceback.print_exc()) 
  • TI12-security/trunk/python/Tests/etreewss/client/fred_eg.py

    r4035 r4038  
    1919wsuNS='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' 
    2020env.set('xmlns:wsu', wsuNS) 
    21 body.set('wsu:Id', '#body') 
     21env.set('URI', "http://blah") 
     22#body.set('wsu:Id', '#body') 
     23body.set('{%s}Id' % wsuNS, '#body') 
    2224ns = {'wsu': wsuNS} 
    2325print "wsu:Id elements = %s" % env.findall('.//*[@wsu:Id]', namespaces=ns) 
     
    3840print "wsu:Id elements = %s" % env2.findall('.//*[@wsu:Id]', namespaces=ns) 
    3941 
     42print "Calling C14N for echo message ..." 
     43import pdb;pdb.set_trace() 
     44 
     45etree = ElementC14N.parse('/home/pjkersha/Desktop/soap-etree.xml') 
     46f = StringIO() 
     47elem = etree.getroot() 
     48elem._scope = etree._scope 
     49ElementC14N.write(ElementC14N.build_scoped_tree(elem), f) 
     50print f.getvalue() 
    4051 
    4152 
     53 
  • TI12-security/trunk/python/Tests/etreewss/server/echoServer.py

    r4024 r4038  
    77 
    88# Import the ZSI stuff you'd need no matter what 
    9 from ZSI.ServiceContainer import ServiceContainer 
     9from ZSI.ServiceContainer import ServiceContainer, SOAPRequestHandler, \ 
     10                                SOAPContext, _contexts, SimpleWSResource, \ 
     11                                ServiceInterface 
    1012 
    1113# This is a new method imported to show it's value 
     
    1517    EchoService as _EchoService 
    1618 
    17 from ndg.security.common import wsSecurity 
     19from ndg.security.common.wssecurity.etree import SignatureHandler 
     20from ndg.security.common.zsi_utils.elementtreeproxy import ElementTreeProxy 
    1821 
    1922from os.path import expandvars as xpdVars 
    2023from os.path import join as jnPath 
    2124mkPath = lambda file: jnPath(os.environ['NDGSEC_WSSESRV_UNITTEST_DIR'], file) 
     25 
     26 
     27import thread 
     28from ZSI.address import Address 
     29from ZSI.parse import ParsedSoap 
     30from ZSI.writer import SoapWriter 
     31from ZSI import ParseException, FaultFromException, FaultFromZSIException, \ 
     32                Fault 
     33                 
     34import logging 
     35logging.basicConfig(level=logging.DEBUG) 
     36log = logging.getLogger(__name__) 
     37 
     38class ElementTreeSOAPRequestHandler(SOAPRequestHandler): 
     39    '''Override SOAPRequestHandler to enable use of ElementTree for parser 
     40    and writer''' 
     41     
     42    def do_POST(self): 
     43        '''The POST command. 
     44        action -- SOAPAction(HTTP header) or wsa:Action(SOAP:Header) 
     45        ''' 
     46        soapAction = self.headers.getheader('SOAPAction') 
     47        post = self.path 
     48        if not post: 
     49            raise PostNotSpecified, 'HTTP POST not specified in request' 
     50        if soapAction: 
     51            soapAction = soapAction.strip('\'"') 
     52        post = post.strip('\'"') 
     53        try: 
     54            ct = self.headers['content-type'] 
     55            if ct.startswith('multipart/'): 
     56                cid = resolvers.MIMEResolver(ct, self.rfile) 
     57                xml = cid.GetSOAPPart() 
     58                ps = ParsedSoap(xml,  
     59                                resolver=cid.Resolve, 
     60                                readerclass=ElementTreeProxy) 
     61            elif self.headers.get('transfer-encoding') == 'chunked': 
     62                # read content length from first line 
     63                hexLength = self.rfile.readline() 
     64                length = int(hexLength, 16) 
     65                xml = self.rfile.read(length) 
     66                ps = ParsedSoap(xml, readerclass=ElementTreeProxy) 
     67            else: 
     68                length = int(self.headers['content-length']) 
     69                xml = self.rfile.read(length) 
     70                ps = ParsedSoap(xml, readerclass=ElementTreeProxy) 
     71        except ParseException, e: 
     72            self.send_fault(FaultFromZSIException(e)) 
     73        except Exception, e: 
     74            # Faulted while processing; assume it's in the header. 
     75            self.send_fault(FaultFromException(e, 1, sys.exc_info()[2])) 
     76        else: 
     77            # Keep track of calls 
     78            thread_id = thread.get_ident() 
     79            _contexts[thread_id] = SOAPContext(self.server, xml, ps, 
     80                                               self.connection, 
     81                                               self.headers, soapAction) 
     82 
     83            try: 
     84                _Dispatch(ps, self.server, self.send_xml, self.send_fault,  
     85                    post=post, action=soapAction) 
     86            except Exception, e: 
     87                self.send_fault(FaultFromException(e, 0, sys.exc_info()[2])) 
     88 
     89            # Clean up after the call 
     90            if _contexts.has_key(thread_id): 
     91                del _contexts[thread_id] 
     92 
     93def _Dispatch(ps, server, SendResponse, SendFault, post, action, nsdict={},  
     94              **kw): 
     95    '''Redefine ZSI.Container._Dispatch to enable use of ElementTree for  
     96    SoapWriter 
     97    ''' 
     98    localURL = 'http://%s:%d%s' %(server.server_name,server.server_port,post) 
     99    address = action 
     100    service = server.getNode(post) 
     101    isWSResource = False 
     102    if isinstance(service, SimpleWSResource): 
     103        isWSResource = True 
     104        service.setServiceURL(localURL) 
     105        address = Address() 
     106        try: 
     107            address.parse(ps) 
     108        except Exception, e: 
     109            return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
     110        if action and action != address.getAction(): 
     111            e = WSActionException('SOAP Action("%s") must match WS-Action("%s") if specified.' \ 
     112                %(action,address.getAction())) 
     113            return SendFault(FaultFromException(e, 0, None), **kw) 
     114        action = address.getAction() 
     115 
     116    if isinstance(service, ServiceInterface) is False: 
     117        e = NoSuchService('no service at POST(%s) in container: %s' %(post,server)) 
     118        return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
     119 
     120    if not service.authorize(None, post, action): 
     121        return SendFault(Fault(Fault.Server, "Not authorized"), code=401) 
     122        #try: 
     123        #    raise NotAuthorized() 
     124        #except Exception, e: 
     125            #return SendFault(FaultFromException(e, 0, None), code=401, **kw) 
     126            ##return SendFault(FaultFromException(NotAuthorized(), 0, None), code=401, **kw) 
     127 
     128    try: 
     129        method = service.getOperation(ps, address) 
     130    except Exception, e: 
     131        return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
     132 
     133    try: 
     134        if isWSResource is True:  
     135            result = method(ps, address) 
     136        else:  
     137            result = method(ps) 
     138    except Exception, e: 
     139        return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
     140 
     141    # Verify if Signed 
     142    service.verify(ps) 
     143 
     144    # If No response just return. 
     145    if result is None: 
     146        return 
     147 
     148    sw = SoapWriter(nsdict=nsdict, writerclass=ElementTreeProxy) 
     149    try: 
     150        sw.serialize(result) 
     151    except Exception, e: 
     152        return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
     153 
     154    if isWSResource is True: 
     155        action = service.getResponseAction(action) 
     156        addressRsp = Address(action=action) 
     157        try: 
     158            addressRsp.setResponseFromWSAddress(address, localURL) 
     159            addressRsp.serialize(sw) 
     160        except Exception, e: 
     161            return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
     162 
     163    # Create Signatures 
     164    service.sign(sw) 
     165 
     166    try: 
     167        soapdata = str(sw) 
     168        return SendResponse(soapdata, **kw) 
     169    except Exception, e: 
     170        return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
    22171 
    23172 
     
    43192        '''\ 
    44193        Overrides ServiceInterface class method to allow signature  
    45         verification'''       
     194        verification''' 
    46195        self.signatureHandler.verify(ps) 
    47196         
     
    99248    # Create the Inherited version of the server 
    100249    echo = EchoService() 
    101     echo.signatureHandler = wsSecurity.SignatureHandler(cfg=wsseCfgFilePath) 
     250    echo.signatureHandler = SignatureHandler(cfgFilePath=wsseCfgFilePath) 
    102251 
    103252    serviceContainer.setNode(echo, url=path) 
     253    serviceContainer.RequestHandlerClass = ElementTreeSOAPRequestHandler 
    104254     
    105255    try: 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/etree.py

    r4035 r4038  
    1 """WS-Security test class includes digital signature handler 
     1"""WS-Security digital signature handler for ElementTree XML package 
    22 
    33NERC Data Grid Project 
    44""" 
    55__author__ = "P J Kershaw" 
    6 __date__ = "01/09/06" 
    7 __copyright__ = "(C) 2007 STFC & NERC" 
     6__date__ = "02/07/08" 
     7__copyright__ = "(C) 2008 STFC & NERC" 
    88__license__ = \ 
    99"""This software may be distributed under the terms of the Q Public  
     
    1818from M2Crypto import X509, BIO, RSA 
    1919import base64 
     20 
     21from elementtree import ElementTree, ElementC14N 
     22from StringIO import StringIO 
    2023 
    2124# Conditional import as this is required for the encryption 
     
    4043from ZSI.wstools.Namespaces import DSIG, ENCRYPTION, WSU, WSA200403, \ 
    4144                                   SOAP, SCHEMA # last included for xsi 
    42  
     45                                    
     46from ZSI.wstools.Namespaces import WSU as _WSU 
    4347from ZSI.wstools.Namespaces import OASIS as _OASIS 
    4448                                   
     
    5559from xml.xpath.Context import Context 
    5660from xml import xpath 
    57  
    58 # Include for re-parsing doc ready for canonicalization in sign method - see 
    59 # associated note 
    60 from xml.dom.ext.reader.PyExpat import Reader 
    6161 
    6262# Enable settings from a config file 
     
    7777    BLOCK_TRIPLEDES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" 
    7878 
    79 class _WSU(WSU): 
     79class WSU(_WSU): 
    8080    '''Try different utility namespace for use with WebSphere''' 
    8181    #UTILITY = "http://schemas.xmlsoap.org/ws/2003/06/utility" 
    82     UTILITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
     82    UTILITY = \ 
     83"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
    8384 
    8485class OASIS(_OASIS): 
    8586    # wss4j 1.5.3 
    86     WSSE11 = "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" 
     87    WSSE11 = \ 
     88    "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" 
    8789    # wss4j 1.5.1 
    8890    #WSSE11 = "http://docs.oasis-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-secext-1.1.xsd" 
     
    110112 
    111113 
    112  
    113114class WSSecurityError(Exception): 
    114115    """For WS-Security generic exceptions not covered by other exception 
    115116    classes in this module""" 
    116117 
    117 class InvalidCertChain(Exception):     
     118class InvalidCertChain(WSSecurityError):     
    118119    """Raised from SignatureHandler.verify if the certificate submitted to 
    119120    verify a signature is not from a known CA""" 
    120121     
    121 class VerifyError(Exception): 
     122class VerifyError(WSSecurityError): 
    122123    """Raised from SignatureHandler.verify if an error occurs in the signature 
    123124    verification""" 
    124   
    125 class TimestampError(Exception): 
     125 
     126class NoSignatureFound(WSSecurityError):  
     127    """Incoming message to be verified was not signed""" 
     128     
     129class TimestampError(WSSecurityError): 
    126130    """Raised from SignatureHandler._verifyTimestamp if there is a problem with 
    127131    the created or expiry times in an input message Timestamp""" 
    128132     
    129 class InvalidSignature(Exception): 
     133class InvalidSignature(WSSecurityError): 
    130134    """Raised from verify method for an invalid signature""" 
    131135 
    132 class SignatureError(Exception): 
     136class SignatureError(WSSecurityError): 
    133137    """Flag if an error occurs during signature generation""" 
    134138         
     
    160164    } 
    161165 
     166    binSecTokEncType = \ 
     167"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" 
    162168 
    163169    #_________________________________________________________________________ 
     
    234240         
    235241        @param refC14nKw: dictionary of keywords to reference  
    236         Canonicalization.  Use 'unsuppressedPrefixes' keyword to set  
    237         unsuppressedPrefixes. 
     242        Canonicalization.  Use 'inclusive_namespaces' keyword to set  
     243        inclusive_namespaces. 
    238244        @type refC14nKw: dict 
    239245         
     
    268274        # TODO: get rid of refC14nKw and signedInfoC14nKw options 
    269275        if len(self.cfg.get('refC14nInclNS', [])): 
    270             self.__setRefC14nKw({'unsuppressedPrefixes': 
     276            self.__setRefC14nKw({'inclusive_namespaces': 
    271277                                 self.cfg['refC14nInclNS']}) 
    272278        else: 
     
    275281    
    276282        if len(self.cfg.get('signedInfoC14nNS', [])): 
    277             self.__setSignedInfoC14nKw({'unsuppressedPrefixes': 
     283            self.__setSignedInfoC14nKw({'inclusive_namespaces': 
    278284                                        self.cfg['signedInfoC14nNS']}) 
    279285        else: 
     
    358364                "Expecting dictionary type for reference c14n keywords" 
    359365                 
    360         elif kw.get('unsuppressedPrefixes') and \ 
    361              not isinstance(kw['unsuppressedPrefixes'], list) and \ 
    362              not isinstance(kw['unsuppressedPrefixes'], tuple): 
     366        elif kw.get('inclusive_namespaces') and \ 
     367             not isinstance(kw['inclusive_namespaces'], list) and \ 
     368             not isinstance(kw['inclusive_namespaces'], tuple): 
    363369            raise AttributeError, \ 
    364370                'Expecting list or tuple of prefix names for "%s" keyword' % \ 
    365                 'unsuppressedPrefixes' 
     371                'inclusive_namespaces' 
    366372         
    367373                 
     
    391397    def __refC14nIsExcl(self): 
    392398        return isinstance(self.__refC14nKw, dict) and \ 
    393                isinstance(self.__refC14nKw.get('unsuppressedPrefixes'), list) 
     399               isinstance(self.__refC14nKw.get('inclusive_namespaces'), list) 
    394400                
    395401    refC14nIsExcl = property(fget=__refC14nIsExcl, 
     
    400406    def __signedInfoC14nIsExcl(self): 
    401407        return isinstance(self.__signedInfoC14nKw, dict) and \ 
    402         isinstance(self.__signedInfoC14nKw.get('unsuppressedPrefixes'), list) 
     408        isinstance(self.__signedInfoC14nKw.get('inclusive_namespaces'), list) 
    403409                
    404410    signedInfoC14nIsExcl = property(fget=__signedInfoC14nIsExcl, 
     
    708714            return 
    709715         
    710         sigConfirmElem = wsseElem.createAppendElement(OASIS.WSSE11,  
    711                                                       'SignatureConfirmation') 
     716        sigConfirmElem = ElementTree.Element("{%s}%s" % (OASIS.WSSE11,  
     717                                                      'SignatureConfirmation')) 
     718        wsseElem.append(sigConfirmElem) 
    712719         
    713720        # Add ID so that the element can be included in the signature 
    714         sigConfirmElem._etree.set('wsu:Id', "signatureConfirmation") 
     721        sigConfirmElem.set('{%s}Id' % WSU.UTILITY, "signatureConfirmation") 
    715722 
    716723        # Add ID so that the element can be included in the signature 
    717         # Following line is a hck to avoid appearance of #x when serialising \n 
    718         # chars TODO: why is this happening?? 
     724        # Following line is a hack to avoid appearance of #x when serialising  
     725        # \n chars  
     726        # TODO: Fix #x problem with sig value? 
    719727        b64EncSignatureValue = ''.join(self.b64EncSignatureValue.split('\n')) 
    720         sigConfirmElem._etree.set('Value', b64EncSignatureValue) 
     728        sigConfirmElem.set('Value', b64EncSignatureValue) 
    721729         
    722730         
     
    736744        ''' 
    737745        # Nb. wsu ns declaration is in the SOAP header elem 
    738         timestampElem = wsseElem.createAppendElement(_WSU.UTILITY, 'Timestamp') 
    739  
     746        timestampElem = ElementTree.Element("{%s}%s"%(WSU.UTILITY,'Timestamp')) 
     747        wsseElem.append(timestampElem) 
     748         
    740749        # Add ID so that the timestamp element can be included in the signature 
    741         timestampElem._etree.set('wsu:Id', "timestamp") 
     750        timestampElem.set('{%s}Id' % WSU.UTILITY, "timestamp") 
    742751         
    743752        # Value type can be any be any one of those supported via  
    744753        # binSecTokValType 
    745         createdElem = timestampElem.createAppendElement(_WSU.UTILITY,'Created') 
     754        createdElem = ElementTree.Element("{%s}%s" % (WSU.UTILITY,'Created')) 
     755        timestampElem.append(createdElem) 
     756         
    746757        dtCreatedTime = datetime.utcnow() 
    747         createdElem.createAppendTextNode(dtCreatedTime.isoformat('T')+'Z') 
     758        createdElem.text = dtCreatedTime.isoformat('T') + 'Z' 
    748759         
    749760        dtExpiryTime = dtCreatedTime + timedelta(seconds=elapsedSec) 
    750         expiresElem = timestampElem.createAppendElement(_WSU.UTILITY,'Expires') 
    751         expiresElem.createAppendTextNode(dtExpiryTime.isoformat('T')+'Z') 
     761        expiresElem = ElementTree.Element("{%s}%s" % (WSU.UTILITY, 'Expires')) 
     762        timestampElem.append(expiresElem) 
     763         
     764        expiresElem.text = dtExpiryTime.isoformat('T') + 'Z' 
    752765         
    753766 
     
    817830         
    818831        # Namespaces for XPath searches 
    819         processorNss = \ 
     832        processorNSs = \ 
    820833        { 
    821             'ds':     DSIG.BASE,  
    822             'wsu':    _WSU.UTILITY,  
    823             'wsse':   OASIS.WSSE,  
    824             'SOAP-ENV':"http://schemas.xmlsoap.org/soap/envelope/"  
     834            'ds':       DSIG.BASE,  
     835            'wsu':      WSU.UTILITY,  
     836            'wsse':     OASIS.WSSE,  
     837            'SOAP-ENV': SOAP.ENV  
    825838        } 
    826839 
    827840        # Add X.509 cert as binary security token 
     841        # TODO: sub encodestring with b64encode? 
    828842        if self.__reqBinSecTokValType==self.binSecTokValType['X509PKIPathv1']: 
    829843            binSecTokVal = base64.encodestring(self.__signingCertChain.asDER()) 
     
    832846            binSecTokVal = base64.encodestring(self.__signingCert.asDER()) 
    833847 
    834         soapWriter._header.setNamespaceAttribute('wsse', OASIS.WSSE) 
    835         soapWriter._header.setNamespaceAttribute('wsse11', OASIS.WSSE11) 
    836         soapWriter._header.setNamespaceAttribute('wsu', _WSU.UTILITY) 
    837         soapWriter._header.setNamespaceAttribute('ds', DSIG.BASE) 
     848        self._soapEnvElem = soapWriter.dom._elem 
     849        soapHdrElem = soapWriter._header._elem 
     850        soapBodyElem = soapWriter.body._elem 
     851         
     852        self._soapEnvElem.set("xmlns:%s" % 'ds', DSIG.BASE) 
     853        #self._soapEnvElem.set("xmlns:%s" % 'wsse', OASIS.WSSE) 
     854         
     855        soapHdrElem.set("xmlns:%s" % 'wsse', OASIS.WSSE) 
     856        soapHdrElem.set("xmlns:%s" % 'wsse11', OASIS.WSSE11) 
     857        soapHdrElem.set("xmlns:%s" % 'wsu', WSU.UTILITY) 
     858        soapHdrElem.set("xmlns:%s" % 'ds', DSIG.BASE) 
    838859         
    839860        try: 
    840             refC14nPfxSet = len(self.__refC14nKw['unsuppressedPrefixes']) > 0 
     861            refC14nPfxSet = len(self.__refC14nKw['inclusive_namespaces']) > 0 
    841862        except KeyError: 
    842863            refC14nPfxSet = False 
     
    844865        try: 
    845866            signedInfoC14nPfxSet = \ 
    846                 len(self.__signedInfoC14nKw['unsuppressedPrefixes']) > 0 
     867                len(self.__signedInfoC14nKw['inclusive_namespaces']) > 0 
    847868        except KeyError: 
    848869            signedInfoC14nPfxSet = False 
    849870                 
    850         if refC14nPfxSet or refC14nPfxSet: 
    851            soapWriter._header.setNamespaceAttribute('ec', DSIG.C14N_EXCL) 
    852          
     871        if refC14nPfxSet: 
     872            soapHdrElem.set("xmlns:%s" % 'ec', DSIG.C14N_EXCL) 
     873             
     874             
    853875        # Check <wsse:security> isn't already present in header 
    854         wsseNodes = soapWriter.dom.evaluate('.//wsse:security', 
    855                                             processorNss=processorNss) 
    856         if len(wsseNodes) > 1: 
     876        wsseElems = self._soapEnvElem.findall('.//wsse:security', 
     877                                              namespaces=processorNSs) 
     878        if len(wsseElems) > 1: 
    857879            raise SignatureError('wsse:Security element is already present') 
    858  
     880         
    859881        # Add WSSE element 
    860         wsseElem = soapWriter._header.createAppendElement(OASIS.WSSE,  
    861                                                           'Security') 
    862         wsseElem.setNamespaceAttribute('wsse', OASIS.WSSE) 
     882        wsseElem = ElementTree.Element("{%s}%s" % (OASIS.WSSE, 'Security')) 
     883        soapHdrElem.append(wsseElem) 
     884         
     885        wsseElem.set("xmlns:%s" % 'wsse', OASIS.WSSE) 
    863886         
    864887        # Recipient MUST parse and check this signature  
    865         wsseElem._etree.set('SOAP-ENV:mustUnderstand', "1") 
     888        wsseElem.set('SOAP-ENV:mustUnderstand', "1") 
    866889         
    867890        # Binary Security Token element will contain the X.509 cert  
    868891        # corresponding to the private key used to sing the message 
    869         binSecTokElem = wsseElem.createAppendElement(OASIS.WSSE,  
    870                                                      'BinarySecurityToken') 
     892        binSecTokElem = ElementTree.Element("{%s}%s" % (OASIS.WSSE,  
     893                                                        'BinarySecurityToken')) 
     894        wsseElem.append(binSecTokElem) 
    871895         
    872896        # Value type can be any be any one of those supported via  
    873897        # binSecTokValType 
    874         binSecTokElem._etree.set('ValueType', self.__reqBinSecTokValType) 
    875  
    876         encodingType = \ 
    877 "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" 
    878         binSecTokElem._etree.set('EncodingType', encodingType) 
     898        binSecTokElem.set('ValueType', self.__reqBinSecTokValType) 
     899        binSecTokElem.set('EncodingType', SignatureHandler.binSecTokEncType) 
    879900         
    880901        # Add ID so that the binary token can be included in the signature 
    881         binSecTokElem._etree.set('wsu:Id', "binaryToken") 
    882  
    883         binSecTokElem.createAppendTextNode(binSecTokVal) 
     902        binSecTokElem.set('{%s}Id' % WSU.UTILITY, "binaryToken") 
     903         
     904        binSecTokElem.text = binSecTokVal 
    884905 
    885906 
     
    893914         
    894915        # Signature 
    895         signatureElem = wsseElem.createAppendElement(DSIG.BASE, 'Signature') 
    896         signatureElem.setNamespaceAttribute('ds', DSIG.BASE) 
     916        signatureElem = ElementTree.Element("{%s}%s" % (DSIG.BASE,'Signature')) 
     917        wsseElem.append(signatureElem) 
    897918         
    898919        # Signature - Signed Info 
    899         signedInfoElem = signatureElem.createAppendElement(DSIG.BASE,  
    900                                                            'SignedInfo') 
     920        signedInfoElem = ElementTree.Element("{%s}%s"%(DSIG.BASE,'SignedInfo')) 
     921        signatureElem.append(signedInfoElem) 
    901922         
    902923        # Signed Info - Canonicalization method 
    903         c14nMethodElem = signedInfoElem.createAppendElement(DSIG.BASE, 
    904                                                     'CanonicalizationMethod') 
     924        c14nMethodElem = ElementTree.Element("{%s}%s" % (DSIG.BASE, 
     925                                                    'CanonicalizationMethod')) 
     926        signedInfoElem.append(c14nMethodElem) 
    905927         
    906928        # Set based on 'signedInfoIsExcl' property 
     
    908930        signedInfoC14nAlg = c14nAlgOpt[int(self.signedInfoC14nIsExcl)] 
    909931         
    910         c14nMethodElem._etree.set('Algorithm', signedInfoC14nAlg) 
     932        c14nMethodElem.set('Algorithm', signedInfoC14nAlg) 
    911933         
    912934        if signedInfoC14nPfxSet: 
    913             c14nInclNamespacesElem = c14nMethodElem.createAppendElement(\ 
    914                                                     signedInfoC14nAlg, 
    915                                                     'InclusiveNamespaces') 
    916             c14nInclNamespacesElem._etree.set('PrefixList',  
    917                 ' '.join(self.__signedInfoC14nKw['unsuppressedPrefixes'])) 
     935            c14nInclNamespacesElem = ElementTree.Element("{%s}%s" % \ 
     936                                                    (signedInfoC14nAlg, 
     937                                                    'InclusiveNamespaces')) 
     938            c14nMethodElem.append(c14nInclNamespacesElem) 
     939             
     940            pfxList = ' '.join(self.__signedInfoC14nKw['inclusive_namespaces']) 
     941            c14nInclNamespacesElem.set('PrefixList', pfxList) 
     942 
    918943         
    919944        # Signed Info - Signature method 
    920         sigMethodElem = signedInfoElem.createAppendElement(DSIG.BASE, 
    921                                                            'SignatureMethod') 
    922         sigMethodElem._etree.set('Algorithm', DSIG.SIG_RSA_SHA1) 
     945        sigMethodElem = ElementTree.Element("{%s}%s" % \ 
     946                                            (DSIG.BASE, 'SignatureMethod')) 
     947        signedInfoElem.append(sigMethodElem) 
     948        sigMethodElem.set('Algorithm', DSIG.SIG_RSA_SHA1) 
    923949         
    924950        # Signature - Signature value 
    925         signatureValueElem = signatureElem.createAppendElement(DSIG.BASE,  
    926                                                              'SignatureValue') 
     951        signatureValueElem = ElementTree.Element("{%s}%s" % (DSIG.BASE,  
     952                                                             'SignatureValue')) 
     953        signatureElem.append(signatureValueElem) 
    927954         
    928955        # Key Info 
    929         KeyInfoElem = signatureElem.createAppendElement(DSIG.BASE, 'KeyInfo') 
    930         secTokRefElem = KeyInfoElem.createAppendElement(OASIS.WSSE,  
    931                                                   'SecurityTokenReference') 
     956        KeyInfoElem = ElementTree.Element("{%s}%s" % (DSIG.BASE, 'KeyInfo')) 
     957        signatureElem.append(KeyInfoElem) 
     958         
     959        secTokRefElem = ElementTree.Element("{%s}%s" % (OASIS.WSSE,  
     960                                                    'SecurityTokenReference')) 
     961        KeyInfoElem.append(secTokRefElem) 
    932962         
    933963        # Reference back to the binary token included earlier 
    934         wsseRefElem = secTokRefElem.createAppendElement(OASIS.WSSE,  
    935                                                         'Reference') 
    936         wsseRefElem._etree.set('URI', "#binaryToken") 
     964        wsseRefElem = ElementTree.Element("{%s}%s" % (OASIS.WSSE, 'Reference')) 
     965        secTokRefElem.append(wsseRefElem) 
     966         
     967        wsseRefElem.set('URI', "#binaryToken") 
    937968         
    938969        # Add Reference to body so that it can be included in the signature 
    939         soapWriter.body._etree.set('wsu:Id', "body") 
    940         soapWriter.body._etree.set('xmlns:wsu', _WSU.UTILITY) 
    941  
    942         # Serialize and re-parse prior to reference generation - calculating 
    943         # canonicalization based on soapWriter.dom.node seems to give an 
    944         # error: the order of wsu:Id attribute is not correct 
    945 #        try: 
    946 #            docNode = Reader().fromString(str(soapWriter)) 
    947 #        except Exception, e: 
    948 #            raise SignatureError("Error parsing SOAP message for signing: %s"%\ 
    949 #                                 e) 
    950 # 
    951 #        ctxt = Context(docNode, processorNss=processorNss) 
    952 #        refNodes = xpath.Evaluate('//*[@wsu:Id]',  
    953 #                                  contextNode=docNode,  
    954 #                                  context=ctxt) 
    955         import pdb;pdb.set_trace() 
    956  
    957         refNodes = soapWriter.dom.evaluate('.//*[@wsu:Id]',  
    958                                            processorNss=processorNss) 
    959          
    960         # Set based on 'signedInfoIsExcl' property 
     970        soapBodyElem.set('xmlns:wsu', WSU.UTILITY) 
     971        soapBodyElem.set('{%s}Id' % WSU.UTILITY, 'body') 
     972 
     973 
     974        # Set Reference Canonicalization algorithm based on 'refC14nIsExcl'  
     975        # property 
    961976        refC14nAlg = c14nAlgOpt[self.refC14nIsExcl] 
    962977         
     978        # Pick up all the wsu:Id tagged elements set in the above 
     979        refElems = self._soapEnvElem.findall('.//*[@wsu:Id]', 
     980                                             namespaces=processorNSs) 
     981 
    963982        # 1) Reference Generation 
    964983        # 
    965984        # Find references 
    966         for refNode in refNodes: 
     985        for refElem in refElems: 
    967986             
    968987            # Set URI attribute to point to reference to be signed 
    969             #uri = u"#" + refNode.getAttribute('wsu:Id') 
    970             uri = u"#" + refNode.attributes[(_WSU.UTILITY, 'Id')].value 
     988            uri = '#' + refElem.get('{%s}%s' % (WSU.UTILITY, 'Id')) 
    971989             
    972990            # Canonicalize reference 
    973 #            refC14n = Canonicalize(refNode, **self.__refC14nKw) 
    974              
    975             refSubsetList = getChildNodes(refNode) 
    976             refC14n = Canonicalize(docNode,  
    977                                    None,  
    978                                    subset=refSubsetList, 
    979                                    **self.__refC14nKw) 
     991#            refC14n = self.canonicalize(subset=refElem, 
     992#                                        exclusive=self.refC14nIsExcl, 
     993#                                        **self.__refC14nKw) 
     994            refC14n = soapWriter.dom.canonicalize(subset=refElem, 
     995                                                  exclusive=self.refC14nIsExcl, 
     996                                                  **self.__refC14nKw) 
     997            log.debug('Canonicalisation for URI "%s": %s', uri, refC14n) 
     998            import pdb;pdb.set_trace() 
    980999             
    9811000            # Calculate digest for reference and base 64 encode 
    9821001            # 
    9831002            # Nb. encodestring adds a trailing newline char 
    984             digestValue = base64.encodestring(sha(refC14n).digest()).strip() 
    985  
    986  
     1003            # Use b64encode instead - encodestring puts in newline chars at 
     1004            # 76 char intervals 
     1005            #digestValue = base64.encodestring(sha(refC14n).digest()).strip() 
     1006            digestValue = base64.b64encode(sha(refC14n).digest()) 
     1007             
    9871008            # Add a new reference element to SignedInfo 
    988             refElem = signedInfoElem.createAppendElement(DSIG.BASE,  
    989                                                          'Reference') 
    990             refElem._etree.set('URI', uri) 
     1009            signedInfoRefElem = ElementTree.Element("{%s}Reference"%DSIG.BASE) 
     1010            signedInfoElem.append(signedInfoRefElem) 
     1011            signedInfoRefElem.set('URI', uri) 
    9911012             
    9921013            # Use ds:Transforms or wsse:TransformationParameters? 
    993             transformsElem = refElem.createAppendElement(DSIG.BASE,  
    994                                                         'Transforms') 
    995             transformElem = transformsElem.createAppendElement(DSIG.BASE,  
    996                                                                'Transform') 
     1014            transformsElem = ElementTree.Element("{%s}Transforms" % DSIG.BASE) 
     1015            signedInfoRefElem.append(transformsElem) 
     1016             
     1017            transformElem = ElementTree.Element("{%s}Transform" % DSIG.BASE) 
     1018            transformsElem.append(transformElem) 
    9971019 
    9981020            # Set Canonicalization algorithm type 
    999             transformElem._etree.set('Algorithm', refC14nAlg) 
     1021            transformElem.set('Algorithm', refC14nAlg) 
    10001022            if refC14nPfxSet: 
    10011023                # Exclusive C14N requires inclusive namespace elements 
     
    10031025                                                       refC14nAlg, 
    10041026                                                       'InclusiveNamespaces') 
    1005                 inclNamespacesElem._etree.set('PrefixList', 
    1006                         ' '.join(self.__refC14nKw['unsuppressedPrefixes'])) 
     1027                refPfxList = ' '.join(self.__refC14nKw['inclusive_namespaces']) 
     1028                inclNamespacesElem.set('PrefixList', refPfxList) 
    10071029             
    10081030            # Digest Method  
    1009             digestMethodElem = refElem.createAppendElement(DSIG.BASE,  
    1010                                                            'DigestMethod') 
    1011             digestMethodElem._etree.set('Algorithm', DSIG.DIGEST_SHA1) 
     1031            digestMethodElem = ElementTree.Element("{%s}%s" % (DSIG.BASE,  
     1032                                                               'DigestMethod')) 
     1033            signedInfoRefElem.append(digestMethodElem) 
     1034             
     1035            digestMethodElem.set('Algorithm', DSIG.DIGEST_SHA1) 
    10121036             
    10131037            # Digest Value 
    1014             digestValueElem = refElem.createAppendElement(DSIG.BASE,  
    1015                                                           'DigestValue') 
    1016             digestValueElem.createAppendTextNode(digestValue) 
    1017  
     1038            digestValueElem = ElementTree.Element("{%s}%s" % (DSIG.BASE,  
     1039                                                              'DigestValue')) 
     1040            signedInfoRefElem.append(digestValueElem) 
     1041            digestValueElem.text = digestValue 
    10181042    
    10191043        # 2) Signature Generation 
    10201044        #         
    10211045        # Canonicalize the signedInfo node 
    1022 #        c14nSignedInfo = Canonicalize(signedInfoElem.node,  
    1023 #                                      **self.__signedInfoC14nKw) 
    1024              
    1025 #        signedInfoSubsetList = getChildNodes(signedInfoElem.node) 
    1026 #        c14nSignedInfo = Canonicalize(soapWriter._header.node,  
    1027 #                                      None,  
    1028 #                                      subset=signedInfoSubsetList, 
    1029 #                                      **self.__signedInfoC14nKw) 
    1030  
    1031         docNode = Reader().fromString(str(soapWriter)) 
    1032         ctxt = Context(docNode, processorNss=processorNss) 
    1033         signedInfoNode = xpath.Evaluate('//ds:SignedInfo',  
    1034                                           contextNode=docNode,  
    1035                                           context=ctxt)[0] 
    1036  
    1037         signedInfoSubsetList = getChildNodes(signedInfoNode) 
    1038         c14nSignedInfo = Canonicalize(docNode,  
    1039                                       None,  
    1040                                       subset=signedInfoSubsetList, 
    1041                                       **self.__signedInfoC14nKw) 
    1042  
     1046        c14nSignedInfo = soapWriter.dom.canonicalize(subset=signedInfoElem, 
     1047                                           exclusive=self.signedInfoC14nIsExcl, 
     1048                                           **self.__signedInfoC14nKw) 
     1049        log.debug('Canonicalisation for <ds:signedInfo>: %s', c14nSignedInfo) 
     1050         
    10431051        # Calculate digest of SignedInfo 
    10441052        signedInfoDigestValue = sha(c14nSignedInfo).digest() 
     
    10461054        # Sign using the private key and base 64 encode the result 
    10471055        signatureValue = self.__signingPriKey.sign(signedInfoDigestValue) 
    1048         b64EncSignatureValue = base64.encodestring(signatureValue).strip() 
     1056         
     1057        # encodestring puts newline markers at 76 char intervals otherwise no  
     1058        # difference 
     1059        # b64EncSignatureValue = base64.encodestring(signatureValue).strip() 
     1060        b64EncSignatureValue = base64.b64encode(signatureValue) 
    10491061 
    10501062        # Add to <SignatureValue> 
    1051         signatureValueElem.createAppendTextNode(b64EncSignatureValue) 
    1052  
    1053         log.info("Signature generation complete") 
     1063        signatureValueElem.text = b64EncSignatureValue 
     1064        log.debug("Signature generation complete") 
    10541065 
    10551066 
     
    10611072        sender""" 
    10621073 
    1063         processorNss = \ 
     1074        processorNSs = \ 
    10641075        { 
    1065             'ds':     DSIG.BASE,  
    1066             'wsu':    _WSU.UTILITY,  
    1067             'wsse':   OASIS.WSSE,  
    1068             'soapenv':"http://schemas.xmlsoap.org/soap/envelope/"  
     1076            'ds':       DSIG.BASE,  
     1077            'wsu':      WSU.UTILITY,  
     1078            'wsse':     OASIS.WSSE,  
     1079            'soapenv':  SOAP.ENV 
    10691080        } 
    1070         ctxt = Context(parsedSOAP.dom, processorNss=processorNss) 
    1071          
    1072  
    1073         signatureNodes = xpath.Evaluate('//ds:Signature',  
    1074                                         contextNode=parsedSOAP.dom,  
    1075                                         context=ctxt) 
    1076         if len(signatureNodes) > 1: 
    1077             raise VerifyError, 'Multiple ds:Signature elements found' 
     1081         
     1082        self._soapEnvElem = parsedSOAP.dom._elem 
     1083#        soapHdrElem = parsedSOAP._header._elem 
     1084#        soapBodyElem = parsedSOAP.body._elem 
     1085 
     1086        signatureElems = self._soapEnvElem.findall('.//ds:Signature',  
     1087                                                   namespaces=processorNSs)         
     1088        if len(signatureElems) > 1: 
     1089            raise VerifyError('Multiple <ds:Signature/> elements found') 
    10781090         
    10791091        try: 
    1080             signatureNodes = signatureNodes[0] 
     1092            signatureElems = signatureElems[0] 
    10811093        except: 
    1082             # Message wasn't signed 
    1083             log.warning("Input message wasn't signed!") 
    1084             return 
     1094            # Message wasn't signed - may be possible if peer raised a SOAP 
     1095            # fault 
     1096            raise NoSignatureFound("Input message wasn't signed!") 
     1097 
    10851098         
    10861099        # Two stage process: reference validation followed by signature  
     
    10921105        # Use this later as a back up in case no Canonicalization was set in  
    10931106        # the transforms elements 
    1094         c14nMethodNode = xpath.Evaluate('//ds:CanonicalizationMethod',  
    1095                                         contextNode=parsedSOAP.dom,  
    1096                                         context=ctxt)[0] 
    1097          
    1098         refNodes = xpath.Evaluate('//ds:Reference',  
    1099                                   contextNode=parsedSOAP.dom,  
    1100                                   context=ctxt) 
    1101  
    1102         for refNode in refNodes: 
     1107        c14nMethodElem = self._soapEnvElem.find('.//ds:CanonicalizationMethod',  
     1108                                                namespaces=processorNSs) 
     1109        if c14nMethodElem is None: 
     1110            raise VerifyError("No <ds:Canonicalization/> element found")   
     1111              
     1112        refElems = self._soapEnvElem.findall('.//ds:Reference',  
     1113                                             namespaces=processorNSs) 
     1114        for refElem in refElems: 
    11031115            # Get the URI for the reference 
    1104             refURI = refNode.getAttributeNode('URI').value 
     1116            refURI = refElem.get('URI') 
    11051117                          
    1106             try: 
    1107                 transformsNode = getElements(refNode, "Transforms")[0] 
    1108                 transforms = getElements(transformsNode, "Transform") 
    1109      
    1110                 refAlgorithm = \ 
    1111                             transforms[0].getAttributeNode("Algorithm").value 
    1112             except Exception, e: 
    1113                 raise VerifyError, \ 
    1114             'failed to get transform algorithm for <ds:Reference URI="%s">'%\ 
    1115                         (refURI, str(e)) 
     1118            transformElem = refElem.find('ds:Transforms/ds:Transform', 
     1119                                         namespaces=processorNSs) 
     1120            if transformElem is None: 
     1121                raise VerifyError( 
     1122            'Failed to get transform algorithm for <ds:Reference URI="%s">'%\ 
     1123                        refURI) 
     1124                 
     1125            refAlgorithm = transformElem.get("Algorithm") 
    11161126                 
    11171127            # Add extra keyword for Exclusive canonicalization method 
    1118             refC14nKw = {} 
    1119             if refAlgorithm == DSIG.C14N_EXCL: 
    1120                 try: 
    1121                     # Check for no inclusive namespaces set 
    1122                     inclusiveNS = getElements(transforms[0],  
    1123                                               "InclusiveNamespaces")                     
    1124                     if inclusiveNS: 
    1125                         pfxListAttNode = \ 
    1126                                 inclusiveNS[0].getAttributeNode('PrefixList') 
    1127                              
    1128                         refC14nKw['unsuppressedPrefixes'] = \ 
    1129                                                 pfxListAttNode.value.split() 
    1130                     else: 
    1131                         # Set to empty list to ensure Exclusive C14N is set for 
    1132                         # Canonicalize call 
    1133                         refC14nKw['unsuppressedPrefixes'] = [] 
    1134                 except Exception, e: 
    1135                     raise VerifyError( 
    1136             'failed to handle transform (%s) in <ds:Reference URI="%s">: %s' %\ 
    1137                         (transforms[0], refURI, e)) 
     1128            refC14nKw = dict(exclusive=refAlgorithm == DSIG.C14N_EXCL) 
     1129            if refC14nKw['exclusive']: 
     1130                # Check for no inclusive namespaces set 
     1131                inclusiveNSElem = transformElem.find("InclusiveNamespaces", 
     1132                                                namespaces=processorNSs)                     
     1133                if inclusiveNSElem is not None: 
     1134                    pfxListTxt = inclusiveNSElem.get('PrefixList') 
     1135                    if pfxListTxt is None: 
     1136                        raise VerifyError('Empty InclusiveNamespaces list for'\ 
     1137                                          ' <ds:Reference URI="%s">' % refURI) 
     1138                                                   
     1139                    refC14nKw['inclusive_namespaces'] = pfxListTxt.split() 
     1140                else: 
     1141                    # Set to empty list to ensure Exclusive C14N is set for 
     1142                    # Canonicalize call 
     1143                    refC14nKw['inclusive_namespaces'] = [] 
    11381144         
    11391145            # Canonicalize the reference data and calculate the digest 
    11401146            if refURI[0] != "#": 
    1141                 raise VerifyError, \ 
    1142                     "Expecting # identifier for Reference URI \"%s\"" % refURI 
     1147                raise VerifyError('Expecting # identifier for Reference URI' \ 
     1148                                  ' "%s"' % refURI) 
    11431149                     
    11441150            # XPath reference 
    1145             uriXPath = '//*[@wsu:Id="%s"]' % refURI[1:] 
    1146             uriNode = xpath.Evaluate(uriXPath,  
    1147                                      contextNode=parsedSOAP.dom,  
    1148                                      context=ctxt)[0] 
    1149  
    1150 #            refC14n = Canonicalize(uriNode, **refC14nKw) 
    1151             refSubsetList = getChildNodes(uriNode) 
    1152             refC14n = Canonicalize(parsedSOAP.dom, 
    1153                                    None,  
    1154                                    subset=refSubsetList, 
    1155                                    **refC14nKw) 
    1156             digestValue = base64.encodestring(sha(refC14n).digest()).strip() 
    1157              
    1158             # Extract the digest value that was stored             
    1159             digestNode = getElements(refNode, "DigestValue")[0] 
    1160             nodeDigestValue = str(digestNode.childNodes[0].nodeValue).strip()    
     1151            uriXPath = './/*[@wsu:Id="%s"]' % refURI[1:] 
     1152            uriElem=self._soapEnvElem.findall(uriXPath,namespaces=processorNSs) 
     1153            if len(uriElem) > 1: 
     1154                raise VerifyError("Multiple elements matching '%s' " % \ 
     1155                                  uriXPath + \ 
     1156                                  "search path: %s" % uriElem) 
     1157                 
     1158            refC14n=parsedSOAP.dom.canonicalize(subset=uriElem[0],**refC14nKw) 
     1159             
     1160            # encodestring adds line delimiters at 76 char intervals - avoid  
     1161            # and use b64encode instead             
     1162            calculatedDigestValue = base64.b64encode(sha(refC14n).digest()) 
     1163             
     1164            # Extract the digest value that was stored in the SOAP request          
     1165            digestElem = refElem.find('ds:DigestValue',namespaces=processorNSs) 
     1166            if digestElem is None: 
     1167                raise VerifyError('Failed to get digestValue for ' \ 
     1168                                  '<ds:Reference URI="%s">' % refURI) 
     1169                 
     1170            # Need to check here for value split into separate lines? 
     1171            retrievedDigestValue = str(digestElem.text).strip()    
    11611172             
    11621173            # Reference validates if the two digest values are the same 
    1163             if digestValue != nodeDigestValue: 
    1164                 raise InvalidSignature, \ 
    1165                         'Digest Values do not match for URI: "%s"' % refURI 
    1166              
    1167             log.info("Verified canonicalization for element %s" % refURI[1:]) 
    1168                  
     1174            if retrievedDigestValue != calculatedDigestValue: 
     1175                log.error("Digest values don't match") 
     1176                log.error('Canonicalisation for URI: "%s": %s' % \ 
     1177                          (refURI, refC14n)) 
     1178                import pdb;pdb.set_trace() 
     1179                raise InvalidSignature('Digest Values do not match for URI:' \ 
     1180                                       ' "%s"' % refURI) 
     1181             
     1182            log.debug("Verified canonicalization for element %s" % refURI[1:]) 
     1183             
     1184        else: 
     1185            raise VerifyError("No <ds:Reference/> elements found")   
     1186 
     1187 
    11691188        # 2) Signature Validation 
    1170         signedInfoNode = xpath.Evaluate('//ds:SignedInfo', 
    1171                                         contextNode=parsedSOAP.dom,  
    1172                                         context=ctxt)[0] 
    1173  
     1189        signedInfoElem = self._soapEnvElem.find('.//ds:SignedInfo', 
     1190                                                namespaces=processorNSs) 
     1191        if signedInfoElem is None: 
     1192            raise VerifyError("No <ds:signedInfo/> section found") 
     1193         
    11741194        # Get algorithm used for canonicalization of the SignedInfo  
    11751195        # element.  Nb. This is NOT necessarily the same as that used to 
    11761196        # canonicalize the reference elements checked above! 
    1177         signedInfoC14nAlg = c14nMethodNode.getAttributeNode("Algorithm").value 
    1178         signedInfoC14nKw = {} 
    1179         if signedInfoC14nAlg == DSIG.C14N_EXCL: 
    1180             try: 
    1181                 # Check for inclusive namespaces 
    1182                 inclusiveNS = c14nMethodNode.getElementsByTagName( 
    1183                                                         "InclusiveNamespaces") 
    1184                 if inclusiveNS:                     
    1185                     pfxListAttNode = inclusiveNS[0].getAttributeNode(\ 
    1186                                                                  'PrefixList') 
    1187                     signedInfoC14nKw['unsuppressedPrefixes'] = \ 
    1188                                                 pfxListAttNode.value.split() 
    1189                 else: 
    1190                     # Must default to [] otherwise exclusive C14N is not 
    1191                     # triggered 
    1192                     signedInfoC14nKw['unsuppressedPrefixes'] = [] 
    1193             except Exception, e: 
    1194                 raise VerifyError, \ 
    1195             'failed to handle exclusive canonicalisation for SignedInfo: %s'%\ 
    1196                         str(e) 
     1197        signedInfoC14nAlg = c14nMethodElem.get("Algorithm") 
     1198        if signedInfoC14nAlg is None: 
     1199            raise VerifyError('No Algorithm attribute set for <signedInfo/>' \ 
     1200                              ' section') 
     1201             
     1202        signedInfoC14nKw = dict(exclusive=signedInfoC14nAlg == DSIG.C14N_EXCL) 
     1203        if signedInfoC14nKw['exclusive']: 
     1204 
     1205            # Check for no inclusive namespaces set 
     1206            inclusiveNSElem = c14nMethodElem.find("InclusiveNamespaces", 
     1207                                                  namespaces=processorNSs)                     
     1208            if inclusiveNSElem is not None: 
     1209                pfxListTxt = inclusiveNSElem.get('PrefixList') 
     1210                if pfxListTxt is None: 
     1211                    raise VerifyError('Empty InclusiveNamespaces list for'\ 
     1212                                      ' <ds:Reference URI="%s">' % refURI) 
     1213                                               
     1214                signedInfoC14nKw['inclusive_namespaces'] = pfxListTxt.split() 
     1215            else: 
     1216                # Set to empty list to ensure Exclusive C14N is set for 
     1217                # Canonicalize call 
     1218                signedInfoC14nKw['inclusive_namespaces'] = [] 
    11971219 
    11981220        # Canonicalize the SignedInfo node and take digest 
    1199         #c14nSignedInfo = Canonicalize(signedInfoNode, **signedInfoC14nKw) 
    1200         signedInfoSubsetList = getChildNodes(signedInfoNode) 
    1201         c14nSignedInfo = Canonicalize(parsedSOAP.dom,  
    1202                                       None,  
    1203                                       subset=signedInfoSubsetList, 
    1204                                       **signedInfoC14nKw) 
    1205                                
     1221        c14nSignedInfo = parsedSOAP.dom.canonicalize(subset=signedInfoElem,  
     1222                                                     **signedInfoC14nKw)                       
    12061223        signedInfoDigestValue = sha(c14nSignedInfo).digest() 
    12071224         
    12081225        # Get the signature value in order to check against the digest just 
    12091226        # calculated 
    1210         signatureValueNode = xpath.Evaluate('//ds:SignatureValue', 
    1211                                             contextNode=parsedSOAP.dom,  
    1212                                             context=ctxt)[0] 
     1227        signatureValueElem = self._soapEnvElem.find('//ds:SignatureValue', 
     1228                                                    namespaces=processorNSs) 
    12131229 
    12141230        # Remove base 64 encoding 
    1215         # This line necessary? - only decode call needed??  pyGridWare vers 
    1216         # seems to preserve whitespace 
    1217 #        b64EncSignatureValue = \ 
    1218 #                    str(signatureValueNode.childNodes[0].nodeValue).strip() 
    1219         b64EncSignatureValue = signatureValueNode.childNodes[0].nodeValue 
     1231        b64EncSignatureValue = signatureValueElem.text 
    12201232        signatureValue = base64.decodestring(b64EncSignatureValue) 
    12211233 
     
    12281240            self.b64EncSignatureValue = None 
    12291241          
    1230         # Look for X.509 Cert in wsse:BinarySecurityToken node 
    1231         try: 
    1232             binSecTokNode = xpath.Evaluate('//wsse:BinarySecurityToken', 
    1233                                            contextNode=parsedSOAP.dom, 
    1234                                            context=ctxt)[0] 
    1235         except: 
    1236             # Signature may not have included the Binary Security Token in  
    1237             # which case the verifying cert will need to have been set  
    1238             # elsewhere 
    1239             binSecTokNode = None 
    1240          
    1241         if binSecTokNode: 
    1242             try: 
    1243                 x509CertTxt=str(binSecTokNode.childNodes[0].nodeValue) 
    1244                  
    1245                 valueType = binSecTokNode.getAttributeNode("ValueType").value 
    1246                 if valueType in (self.__class__.binSecTokValType['X509v3'], 
    1247                                  self.__class__.binSecTokValType['X509']): 
    1248                     # Remove base 64 encoding 
    1249                     derString = base64.decodestring(x509CertTxt) 
    1250                      
    1251                     # Load from DER format into M2Crypto.X509 
    1252                     m2X509Cert = X509.load_cert_string(derString, 
    1253                                                        format=X509.FORMAT_DER) 
    1254                     self.__setVerifyingCert(m2X509Cert) 
    1255                      
    1256                     x509Stack = X509Stack() 
    1257  
    1258                 elif valueType == \ 
    1259                     self.__class__.binSecTokValType['X509PKIPathv1']: 
    1260                      
    1261                     derString = base64.decodestring(x509CertTxt) 
    1262                     x509Stack = X509StackParseFromDER(derString) 
    1263                      
    1264                     # TODO: Check ordering - is the last off the stack the 
    1265                     # one to use to verify the message? 
    1266                     self.__verifyingCert = x509Stack[-1] 
    1267                 else: 
    1268                     raise WSSecurityError, "BinarySecurityToken ValueType " +\ 
    1269                         'attribute is not recognised: "%s"' % valueType 
    1270                                 
    1271             except Exception, e: 
    1272                 raise VerifyError, "Error extracting BinarySecurityToken " + \ 
    1273                                    "from WSSE header: " + str(e) 
     1242        # Look for X.509 Cert in wsse:BinarySecurityToken element -  
     1243        # Signature may not have included the Binary Security Token in  
     1244        # which case the verifying cert will need to have been set  
     1245        # elsewhere 
     1246        binSecTokElem = self._soapEnvElem.find('.//wsse:BinarySecurityToken', 
     1247                                               namespaces=processorNSs)         
     1248        if binSecTokElem is not None: 
     1249            x509CertTxt = str(binSecTokElem.text) 
     1250             
     1251            valueType = binSecTokElem.get("ValueType") 
     1252            if valueType in (SignatureHandler.binSecTokValType['X509v3'], 
     1253                             SignatureHandler.binSecTokValType['X509']): 
     1254                # Remove base 64 encoding 
     1255                derString = base64.decodestring(x509CertTxt) 
     1256                 
     1257                # Load from DER format into M2Crypto.X509 
     1258                m2X509Cert = X509.load_cert_string(derString, 
     1259                                                   format=X509.FORMAT_DER) 
     1260                self.__setVerifyingCert(m2X509Cert) 
     1261                 
     1262                x509Stack = X509Stack() 
     1263 
     1264            elif valueType == \ 
     1265                SignatureHandler.binSecTokValType['X509PKIPathv1']: 
     1266                 
     1267                derString = base64.decodestring(x509CertTxt) 
     1268                x509Stack = X509StackParseFromDER(derString) 
     1269                 
     1270                # TODO: Check ordering - is the last off the stack the 
     1271                # one to use to verify the message? 
     1272                self.__verifyingCert = x509Stack[-1] 
     1273            else: 
     1274                raise WSSecurityError('BinarySecurityToken ValueType ' \ 
     1275                    'attribute is not recognised: "%s"' % valueType) 
    12741276 
    12751277        if self.__verifyingCert is None: 
    1276             raise VerifyError, "No certificate set for verification " + \ 
    1277                 "of the signature" 
     1278            raise VerifyError("No certificate set for verification of the " \ 
     1279                              "signature") 
    12781280         
    12791281        # Extract RSA public key from the cert 
     
    12841286            verify = rsaPubKey.verify(signedInfoDigestValue, signatureValue) 
    12851287        except RSA.RSAError, e: 
    1286             raise VerifyError, "Error in Signature: " + str(e) 
     1288            raise VerifyError("Error in Signature: " + str(e)) 
    12871289         
    12881290        if not verify: 
    1289             raise InvalidSignature, "Invalid signature" 
     1291            raise InvalidSignature("Invalid signature") 
    12901292         
    12911293        # Verify chain of trust  
     
    12951297        self._verifyTimeStamp(parsedSOAP, ctxt)  
    12961298        log.info("Signature OK")         
     1299 
     1300 
     1301    def canonicalize(self, **kw): 
     1302        '''ElementTree based Canonicalization - See ElementC14N for keyword 
     1303        info''' 
     1304        f = StringIO() 
     1305        ElementC14N.write(ElementC14N.build_scoped_tree(self._soapEnvElem),  
     1306                          f,  
     1307                          **kw) 
     1308        return f.getvalue() 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/zsi_utils/elementtreeproxy.py

    r4024 r4038  
    77from elementtree import ElementC14N, ElementTree 
    88from StringIO import StringIO 
     9 
     10from xml.dom import Node # Enable mimic of xml.dom behaviour 
    911 
    1012 
     
    2123    _soap_enc_nsuri = SOAP.ENC 
    2224 
    23     def __init__(self, sw, message=None): 
    24         '''Initialize.  
    25            sw -- SoapWriter 
    26         ''' 
    27         assert message is None, 'TODO' 
    28         self._etree = None 
    29  
     25    def __init__(self, message=None, etree=None, elem=None): 
     26        '''Initialize''' 
     27        self._etree = etree 
     28        self._elem = elem 
     29         
     30        # Flag to enable correct behaviour for DOM childNodes 
     31        self._treeRoot = False 
     32         
     33        if isinstance(etree, ElementTree.ElementTree) and elem is None: 
     34            self._elem = etree.getroot() 
     35        elif isinstance(elem, ElementTree.Element) and etree is None: 
     36            self._etree = ElementTree.ElementTree(element=elem) 
     37             
     38         
    3039    def __str__(self): 
    3140        return self.toString() 
    3241         
    3342    def toString(self): 
    34         return ElementTree.tostring(self._etree) 
    35  
     43        return self.canonicalize() 
     44     
    3645    ############################################# 
    3746    #Methods used in TypeCodes 
     
    5362            # Search for matching prefix 
    5463            matchingPrefix = None 
    55             for elem in self._etree.getiterator(): 
     64            for elem in self._elem.getiterator(): 
    5665                for k, v in elem.items(): 
    5766                    if k.startswith("xmlns:") and v == namespaceURI: 
     
    6574                matchingPrefix = prefix 
    6675 
    67             self._etree.set("xmlns:%s" % matchingPrefix, namespaceURI)                 
     76            elem.set("xmlns:%s" % matchingPrefix, namespaceURI)                 
    6877        else: 
    6978            assert prefix, "Prefix must be set - no namespaceURI was provided" 
    70             print 'HELLO' 
     79 
    7180            # Search for matching NS 
    7281            for elem in self._etree.getiterator(): 
     
    7786                     
    7887            elem = ElementTree.Element("{%s}%s:%s" % (namespaceURI,  
    79                                                      prefix, 
    80                                                      localName)) 
    81          
    82              
    83         self._etree.append(elem) 
    84          
    85         eproxy = ElementTreeProxy(None) 
    86         eproxy._etree = elem 
     88                                                      prefix, 
     89                                                      localName)) 
     90         
     91             
     92        self._elem.append(elem) 
     93         
     94        eproxy = ElementTreeProxy(etree=self._etree, elem=elem) 
    8795 
    8896        return eproxy 
     
    92100        represented via this interface.  Only 1 possible text node/element 
    93101        ''' 
    94         self._etree.text = pyobj 
     102        self._elem.text = pyobj 
    95103 
    96104    def createDocument(self, namespaceURI=SOAP.ENV, localName='Envelope'): 
     
    98106        prefix = self._soap_env_prefix 
    99107 
    100         self._etree = ElementTree.Element('{%s}%s' %(namespaceURI, localName)) 
    101         self._etree.set("xmlns:%s" % prefix, namespaceURI) 
     108        self._elem = ElementTree.Element('{%s}%s' %(namespaceURI, localName)) 
     109        self._etree = ElementTree.ElementTree(element=self._elem) 
     110        self._elem.set("xmlns:%s" % prefix, namespaceURI) 
    102111         
    103112    def getElement(self, namespaceURI, localName): 
    104         for e in self._etree.getchildren(): 
     113        for e in self._elem.getiterator(): 
    105114            l = e.tag.strip('{').split('}') 
    106115            if not namespaceURI: 
    107116                if len(l) == 1 and l[0] == localName: 
    108                     eproxy = ElementTreeProxy(None) 
    109                     eproxy._etree = e 
     117                    eproxy = ElementTreeProxy(elem=e, etree=self._etree) 
    110118                    return eproxy 
    111119            elif len(l) == 2 and l[0] == namespaceURI and l[1] == localName: 
    112                 eproxy = ElementTreeProxy(None) 
    113                 eproxy._etree = e 
     120                eproxy = ElementTreeProxy(elem=e, etree=self._etree) 
    114121                return eproxy 
    115122                 
     
    119126    def getPrefix(self, namespaceURI): 
    120127        '''TODO: this is not possible w/elementTree since namespace prefix 
    121         mappings aren't done until serialization.  completely abstraced out. 
    122         ''' 
    123         raise NotImplementedError, 'this func isnt going to work' 
     128        mappings aren't done until serialization.  completely abstracted out. 
     129        ''' 
     130        raise NotImplementedError, "this func isn't going to work" 
    124131         
    125132    def setAttributeNS(self, namespaceURI, localName, value): 
     
    132139        '''  
    133140        self._etree.attrib["{%s}%s" %(namespaceURI, localName)] = value 
     141 
     142    def getAttributeNS(self, namespaceURI, localName): 
     143         
     144        return self._elem.get('{%s}%s' % (namespaceURI, localName)) 
    134145         
    135146    def setAttributeType(self, namespaceURI, localName): 
     
    147158        ''' 
    148159        #self._etree.attrib["xmlns:%s" %prefix] = namespaceURI 
    149         self._etree.set("xmlns:%s" % prefix, namespaceURI) 
     160        self._elem.set("xmlns:%s" % prefix, namespaceURI) 
    150161         
    151162    def canonicalize(self, **kw): 
     
    173184#        c14n = f.getvalue() 
    174185#        return c14n 
    175         root = ElementTree.ElementTree(self._etree) 
    176      
    177         root._scope = {} 
    178         root._parent=dict((c, p) for p in self._etree.getiterator() for c in p) 
    179      
    180         # build scope map 
    181         for e in self._etree.getiterator(): 
    182             scope = [] 
    183             for k in e.keys(): 
    184                 if k.startswith("xmlns:"): 
    185                     # move xmlns prefix to scope map 
    186                     scope.append((k[6:], e.get(k))) 
    187                     del e.attrib[k] 
    188             if scope: 
    189                 root._scope[e] = scope 
    190      
    191         # Save as C14N 
     186 
     187#        root = ElementTree.ElementTree(self._etree) 
     188#     
     189#        root._scope = {} 
     190#        root._parent=dict((c, p) for p in self._etree.getiterator() for c in p) 
     191#     
     192#        # build scope map 
     193#        for e in self._etree.getiterator(): 
     194#            scope = [] 
     195#            for k in e.keys(): 
     196#                if k.startswith("xmlns:"): 
     197#                    # move xmlns prefix to scope map 
     198#                    scope.append((k[6:], e.get(k))) 
     199#                    del e.attrib[k] 
     200#            if scope: 
     201#                root._scope[e] = scope 
     202#     
     203#        # Save as C14N 
     204#        f = StringIO() 
     205#        ElementC14N.write(root, f, **kw) 
     206#        c14n = f.getvalue() 
     207#        return c14n 
     208 
     209#        f = StringIO() 
     210#        ElementC14N.write(ElementC14N.build_scoped_tree(self._elem), f, **kw) 
     211#        c14n = f.getvalue() 
     212 
    192213        f = StringIO() 
    193         ElementC14N.write(root, f, **kw) 
     214 
     215        # Check that namespace scope has been added - this will be the case 
     216        # for a parsed message but not true for a document created in memory. 
     217        # In the latter case a call to build the scope is required 
     218        if hasattr(self._etree, '_scope'): 
     219            ElementC14N.write(self._etree, f, **kw) 
     220        else: 
     221            ElementC14N.write(_build_scoped_tree(self._elem), f,  
     222                              **kw) 
     223             
    194224        c14n = f.getvalue() 
     225 
    195226        return c14n 
     227 
    196228     
    197229    def evaluate(self, expression, processorNss=None): 
    198         return self._etree.findall(expression, namespaces=processorNss) 
     230        elemList = self._etree.findall(expression, namespaces=processorNss) 
     231             
     232        return [ElementTreeProxy(elem=elem, etree=self._etree) \ 
     233                for elem in elemList] 
     234     
     235    # Methods to satisfy ParsedSoap interface         
     236    def fromString(self, input): 
     237        '''Required by ParsedSoap to parse a string''' 
     238         
     239        # Use ElementC14N.parse as fromstring doesn't create a scope dict 
     240#        self._elem = ElementTree.fromstring(input) 
     241#        self._etree = ElementTree.ElementTree(self._elem) 
     242        fInput = StringIO() 
     243        fInput.write(input) 
     244        fInput.seek(0) 
     245         
     246        self._etree = ElementC14N.parse(fInput) 
     247        self._elem = self._etree.getroot() 
     248        self._treeRoot = True 
     249        return self 
     250     
     251    def _getChildNodes(self): 
     252        '''childNodes property required by ParsedSoap''' 
     253        if self._elem is None: 
     254            return [] 
     255         
     256        # Check for top of tree 
     257        if self._treeRoot:  
     258            # Return a copy of the top level element with _treeRoot set to  
     259            # False so that the next time this method is called the children of 
     260            # the top level element will be returned instead 
     261            return [ElementTreeProxy(etree=self._etree)] 
     262        else: 
     263            return [ElementTreeProxy(elem=elem, etree=self._etree) \ 
     264                    for elem in list(self._elem)] 
     265                 
     266    childNodes = property(fget=_getChildNodes) 
     267     
     268    def _getNodeType(self): 
     269        '''Minimal implementation to mimic behaviour of xml.dom.Node for  
     270        ParsedSoap interface''' 
     271        return Node.ELEMENT_NODE 
     272     
     273    nodeType = property(fget=_getNodeType) 
     274     
     275    def _getLocalName(self): 
     276        '''Parse localName from element tag of form {NS}localName''' 
     277        return self._elem.tag.split('}')[-1] 
     278     
     279    localName = property(fget=_getLocalName) 
     280     
     281    def _getNamespaceURI(self): 
     282        '''Parse NS from element tag of form {NS}localName''' 
     283        return self._elem.tag.replace('{','').split('}')[0] 
     284     
     285    namespaceURI = property(fget=_getNamespaceURI) 
     286     
     287    def _getAttributes(self): 
     288        '''Mimic attributes DOM attribute but note XML namespace declarations 
     289        are not included in ET 
     290         
     291        TODO: alter parser to keep xmlns declarations''' 
     292        return [] 
     293     
     294    attributes = property(fget=_getAttributes) 
     295 
     296from copy import deepcopy 
     297 
     298def _build_scoped_tree(_elem): 
     299     
     300    # Make a copy because attributes are to be deleted. 
     301    elem = deepcopy(_elem) 
     302    # Deep copy misses out 'attrib' Element attribute 
     303    import pdb;pdb.set_trace() 
     304    for e, _e in zip(elem.getiterator(), _elem.getiterator()): 
     305        e.attrib = _e.attrib.copy() 
     306         
     307    root = ElementTree.ElementTree(elem) 
     308 
     309    # build scope map 
     310    root._scope = {} 
     311    for e in elem.getiterator(): 
     312        scope = [] 
     313        for k in e.keys(): 
     314            if k.startswith("xmlns:"): 
     315                # move xmlns prefix to scope map 
     316                scope.append((k[6:], e.get(k))) 
     317                del e.attrib[k] 
     318        if scope: 
     319            root._scope[e] = scope 
     320    # build parent map 
     321    root._parent = dict((c, p) for p in elem.getiterator() for c in p) 
     322 
     323    return root 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/sso/sso/controllers/wayf.py

    r3960 r4038  
    1515        ''' NDG equivalent to Shibboleth WAYF ''' 
    1616        log.debug("WayfController.index ...") 
     17 
    1718        # Check for return to arg in query.  This is necessary only if the  
    1819        # WAYF query originates from a different service to this one 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/wsSecurity/client/echoClientTest.cfg

    r3652 r4038  
    99[setUp] 
    1010#uri = http://localhost:7100/Echo 
    11 uri = http://localhost:7200/Echo 
     11uri = http://localhost:7000/Echo 
    1212signingPriKeyFilePath = $NDGSEC_WSSECLNT_UNITTEST_DIR/clnt.key 
    1313signingPriKeyPwd =  
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/wsSecurity/server/echoServer.cfg

    r3755 r4038  
    99[setUp] 
    1010hostname = localhost 
    11 #port = 7000 
    12 port = 7100 
     11port = 7000 
     12#port = 7100 
    1313path = /Echo 
    1414wsseCfgFilePath = $NDGSEC_WSSESRV_UNITTEST_DIR/wssecurity.cfg 
Note: See TracChangeset for help on using the changeset viewer.