Ignore:
Timestamp:
31/08/06 16:59:57 (13 years ago)
Author:
pjkersha
Message:

Working version with signature and validation across a SOAP interface.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/Tests/xmlsec/WS-Security/wsSecurity.py

    r1465 r1469  
    11#!/bin/env python 
     2 
     3"""WS-Security test class includes digital signature handler 
     4 
     5NERC Data Grid Project 
     6 
     7P J Kershaw 01/09/06 
     8 
     9Copyright (C) 2006 CCLRC & NERC 
     10 
     11This software may be distributed under the terms of the Q Public License, 
     12version 1.0 or later. 
     13""" 
     14 
     15reposID = '$Id$' 
    216 
    317import re 
     
    822import base64 
    923 
    10 import cElementTree as ElementTree 
    1124import ZSI 
    1225from ZSI.wstools.Namespaces import DSIG, OASIS, GLOBUS, WSU, WSA200403, BEA, \ 
     
    3043from xml import xpath 
    3144 
    32 # Type codes for signature elements 
    33 #from ZSI.TC import _get_global_element_declaration as getGlobalElemDecl 
    34  
    35 #Security = getGlobalElemDecl(OASIS.WSSE, "Security").pyclass 
    36 #KeyInfo = getGlobalElemDecl(DSIG.BASE, "KeyInfo").pyclass 
    37 #Reference = GED(OASIS.WSSE, "Reference").pyclass 
    38 #SecurityReference = GED(OASIS.WSSE, "SecurityTokenReference").pyclass 
    39 #Signature = GED(DSIG.BASE, "Signature").pyclass 
    40  
    41  
    42  
    43  
     45# Include for re-parsing doc ready for canonicalization in sign method - see 
     46# associated note 
     47from xml.dom.ext.reader.PyExpat import Reader 
     48 
     49 
     50class VerifyError(Exception): 
     51    """Raised from SignatureHandler.verify if signature is invalid""" 
     52 
     53class SignatureError(Exception): 
     54    """Flag if an error occurs during signature generation""" 
     55         
    4456class SignatureHandler(object): 
    45      
    46     # Unique token reference 
    47     tokenRef = 10101 
    4857     
    4958    def __init__(self, 
     
    5766        self.__priKeyFilePath = priKeyFilePath 
    5867        self.__priKeyPwd = priKeyPwd 
    59          
    60         self._can_algo = DSIG.C14N 
    61         self._sig_algo = GLOBUS.SIG 
    62         self._dig_algo = DSIG.DIGEST_SHA1 
    63         self._docCtxtID = None 
    64         self._expire_time = 300 
    65         self._setProtocol = False 
    66         self._sign_headers = sign_headers 
    67         self._sign_body = sign_body 
    6868 
    6969 
     
    7979        x509CertStr = x509CertPat.findall(x509Cert.as_pem())[0] 
    8080 
     81        soapWriter._header.setNamespaceAttribute('wsse', OASIS.WSSE) 
     82        soapWriter._header.setNamespaceAttribute('wsu', WSU.UTILITY) 
     83        soapWriter._header.setNamespaceAttribute('ds', DSIG.BASE) 
     84         
     85        wsseElem = soapWriter._header.createAppendElement(OASIS.WSSE,  
     86                                                         'Security') 
     87        wsseElem.setNamespaceAttribute('wsse', OASIS.WSSE) 
     88        wsseElem.node.setAttribute('SOAP-ENV:mustUnderstand', "1") 
     89         
     90        binSecTokElem = wsseElem.createAppendElement(OASIS.WSSE,  
     91                                                     'BinarySecurityToken') 
     92        binSecTokElem.node.setAttribute('ValueType', "wsse:X509v3") 
     93        binSecTokElem.node.setAttribute('EncodingType', "wsse:Base64Binary") 
     94         
     95        # Add ID so that the binary token can be included in the signature 
     96        binSecTokElem.node.setAttribute('wsu:Id', "binaryToken") 
     97 
     98        binSecTokElem.createAppendTextNode(x509CertStr) 
     99 
     100         
     101        # Signature 
     102        signatureElem = wsseElem.createAppendElement(DSIG.BASE, 'Signature') 
     103        signatureElem.setNamespaceAttribute('ds', DSIG.BASE) 
     104         
     105        # Signature - Signed Info 
     106        signedInfoElem = signatureElem.createAppendElement(DSIG.BASE,  
     107                                                           'SignedInfo') 
     108         
     109        # Signed Info - Canonicalization method 
     110        c14nMethodElem = signedInfoElem.createAppendElement(DSIG.BASE, 
     111                                                    'CanonicalizationMethod') 
     112        c14nMethodElem.node.setAttribute('Algorithm', DSIG.C14N) 
     113         
     114        # Signed Info - Signature method 
     115        sigMethodElem = signedInfoElem.createAppendElement(DSIG.BASE, 
     116                                                    'SignatureMethod') 
     117        sigMethodElem.node.setAttribute('Algorithm', DSIG.DIGEST_SHA1) 
     118         
     119        # Signature - Signature value 
     120        signatureValueElem = signatureElem.createAppendElement(DSIG.BASE,  
     121                                                             'SignatureValue') 
     122         
     123        # Key Info 
     124        KeyInfoElem = signatureElem.createAppendElement(DSIG.BASE, 'KeyInfo') 
     125        secTokRefElem = KeyInfoElem.createAppendElement(OASIS.WSSE,  
     126                                                  'SecurityTokenReference') 
     127         
     128        # Reference back to the binary token included earlier 
     129        wsseRefElem = secTokRefElem.createAppendElement(OASIS.WSSE,  
     130                                                        'Reference') 
     131        wsseRefElem.node.setAttribute('URI', "#binaryToken") 
     132         
     133        # Add Reference to body so that it can be included in the signature 
     134        soapWriter.body.node.setAttribute('wsu:Id', "body") 
     135        soapWriter.body.node.setAttribute('xmlns:wsu', WSU.UTILITY) 
     136 
     137 
     138        # Serialize and re-parse prior to reference generation - calculating 
     139        # canonicalization based on soapWriter.dom.node seems to give an 
     140        # error: the order of wsu:Id attribute is not correct 
     141        docNode = Reader().fromString(str(soapWriter)) 
    81142         
    82143        # Namespaces for XPath searches 
    83         soapWriter.dom.processorNss = \ 
     144        processorNss = \ 
    84145        { 
    85146            'ds':     DSIG.BASE,  
     
    88149            'soapenv':"http://schemas.xmlsoap.org/soap/envelope/"  
    89150        } 
    90  
    91         soapWriter._header.setNamespaceAttribute('wsse', OASIS.WSSE) 
    92         soapWriter._header.setNamespaceAttribute('wsu', WSU.UTILITY) 
    93         soapWriter._header.setNamespaceAttribute('ds', DSIG.BASE) 
    94          
    95         wsseElem = soapWriter._header.createAppendElement(OASIS.WSSE,  
    96                                                          'Security') 
    97         wsseElem.setNamespaceAttribute('wsse', OASIS.WSSE) 
    98         wsseElem.node.setAttribute('SOAP-ENV:mustUnderstand', "1") 
    99          
    100         binSecTokElem = wsseElem.createAppendElement(OASIS.WSSE,  
    101                                                      'BinarySecurityToken') 
    102         binSecTokElem.node.setAttribute('ValueType', "wsse:X509v3") 
    103         binSecTokElem.node.setAttribute('EncodingType', "wsse:Base64Binary") 
    104          
    105         # Add ID 
    106         binSecTokElem.node.setAttribute('wsu:Id', "binaryToken") 
    107  
    108         binSecTokElem.createAppendTextNode(x509CertStr) 
    109  
    110          
    111         signatureElem = wsseElem.createAppendElement(DSIG.BASE, 'Signature') 
    112         signatureElem.setNamespaceAttribute('ds', DSIG.BASE) 
    113          
    114         signedInfoElem = signatureElem.createAppendElement(DSIG.BASE,  
    115                                                            'SignedInfo') 
    116         signatureValueElem = signatureElem.createAppendElement(DSIG.BASE,  
    117                                                              'SignatureValue') 
    118          
    119         KeyInfoElem = signatureElem.createAppendElement(DSIG.BASE, 'KeyInfo') 
    120         secTokRefElem = KeyInfoElem.createAppendElement(OASIS.WSSE,  
    121                                                   'SecurityTokenReference') 
    122          
    123         wsseRefElem = secTokRefElem.createAppendElement(OASIS.WSSE,  
    124                                                         'Reference') 
    125         wsseRefElem.node.setAttribute('URI', "#binaryToken") 
    126          
    127         # Add Reference to body 
    128         soapWriter.body.node.setAttribute('wsu:Id', "body") 
    129         soapWriter.body.node.setAttribute('xmlns:wsu', WSU.UTILITY) 
    130          
    131          
     151        ctxt = Context(docNode, processorNss=processorNss) 
     152        idNodes = xpath.Evaluate('//*[@wsu:Id]',  
     153                                 contextNode=docNode,  
     154                                 context=ctxt) 
     155                 
    132156        # 1) Reference Generation 
    133157        # 
    134158        # Find references 
    135         #idNodes = XPath.Compile('//*[@wsu:Id]').evaluate(docCtxt) 
    136         idElems = [soapWriter.body]#[binSecTokElem, soapWriter.body] 
    137         for idElem in idElems: 
     159        for idNode in idNodes: 
    138160             
    139161            # Set URI attribute to point to reference to be signed 
    140             uri = u"#" + idElem.node.getAttribute('wsu:Id') 
     162            #uri = u"#" + idNode.getAttribute('wsu:Id') 
     163            uri = u"#" + idNode.attributes[(WSU.UTILITY, 'Id')].value 
    141164             
    142165            # Canonicalize reference 
    143 #            c14nRef1 = idElem.canonicalize() 
    144             c14nRef = Canonicalize(idElem.node) 
    145             import pdb;pdb.set_trace() 
    146 #            print "Equal? %s" % (c14nRef == c14nRef1) 
    147             print 'idElem' 
    148             print idElem 
    149             print 'c14nRef' 
    150             print c14nRef 
     166            c14nRef = Canonicalize(idNode) 
    151167             
    152168            # Calculate digest for reference and base 64 encode 
     
    168184            tranformElem.node.setAttribute('Algorithm', DSIG.C14N) 
    169185             
    170             refElem.createAppendElement(DSIG.BASE, 'DigestMethod') 
    171             refElem.node.setAttribute('Algorithm', DSIG.DIGEST_SHA1) 
    172              
     186            # Digest Method  
     187            digestMethodElem = refElem.createAppendElement(DSIG.BASE,  
     188                                                           'DigestMethod') 
     189            digestMethodElem.node.setAttribute('Algorithm', DSIG.DIGEST_SHA1) 
     190             
     191            # Digest Value 
    173192            digestValueElem = refElem.createAppendElement(DSIG.BASE,  
    174193                                                          'DigestValue') 
    175194            digestValueElem.createAppendTextNode(digestValue) 
    176195 
    177         
     196    
    178197        # 2) Signature Generation 
    179198        # 
     
    220239        # Check the signature  
    221240#        verify = bool(rsaPubKey.verify(signedInfoDigestValue, signatureValue)) 
    222 #        print soapWriter.dom.node.toprettyxml() 
    223241#         
    224 #        from xml.dom.ext.reader.PyExpat import Reader 
    225 #        Reader().fromString(str(soapWriter)) 
    226 #        import pdb;pdb.set_trace()         
     242#        open('soap.xml', 'w').write(str(soapWriter)) 
     243#        import pdb;pdb.set_trace()  
     244        print "Signature Generated" 
    227245 
    228246 
     
    245263                                        context=ctxt) 
    246264        if len(signatureNodes) > 1: 
    247             raise Exception, 'Multiple ds:Signature elements found' 
     265            raise VerifyError, 'Multiple ds:Signature elements found' 
    248266         
    249267        try: 
     
    285303                    inclusiveNS.getAttributeValue(None, "PrefixList").split() 
    286304                except: 
    287                     raise Exception, \ 
     305                    raise VerifyError, \ 
    288306                'failed to handle transform (%s) in <ds:Reference URI="%s">'%\ 
    289307                        (transforms[0], uri) 
     
    291309            # Canonicalize the reference data and calculate the digest 
    292310            if refURI[0] != "#": 
    293                 raise Exception, \ 
     311                raise VerifyError, \ 
    294312                    "Expecting # identifier for Reference URI \"%s\"" % refURI 
    295313                     
     
    301319 
    302320            c14nRef = Canonicalize(uriNode, **kw) 
    303             import pdb;pdb.set_trace() 
    304321            digestValue = base64.encodestring(sha(c14nRef).digest()).strip() 
    305322             
     
    310327            # Reference validates if the two digest values are the same 
    311328            if digestValue != nodeDigestValue: 
    312                 raise Exception, 'Digest Values do not match for URI: "%s"' %\ 
     329                raise VerifyError, 'Digest Values do not match for URI: "%s"' %\ 
    313330                                                                        refURI 
    314331                 
     
    325342        algorithm = c14nMethodNode.getAttributeNodeNS(None, 'Algorithm').value 
    326343        if algorithm != DSIG.C14N: 
    327             raise Exception, \ 
     344            raise VerifyError, \ 
    328345                "Only \"%s\" canonicalization algorithm supported" % DSIG.C14N 
    329346                 
     
    357374                                           signatureValue)) 
    358375        except RSA.RSAError: 
    359             raise Exception, "Invalid Signature" 
    360  
    361  
    362     def getTokenRefString(self): 
    363         """ 
    364         Return an unique number to identify an element 
    365         for the element's id attribute 
    366         """ 
    367         Signature.tokenRef +=1 
    368         return str(Signature.tokenRef) 
    369  
     376            raise VerifyError, "Invalid Signature" 
     377         
     378        print "Signature OK" 
    370379     
    371380       
Note: See TracChangeset for help on using the changeset viewer.