Changeset 1469


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

Working version with signature and validation across a SOAP interface.

Location:
TI12-security/trunk/python/Tests/xmlsec/WS-Security
Files:
4 edited

Legend:

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

    r1465 r1469  
    11#!/usr/bin/env python 
     2 
     3"""WS-Security test client 
     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 sys, socket 
     
    2640     
    2741    try: 
    28         txResp = binding.Send(None,  
     42        binding.Send(None,  
    2943                 'echo',  
    3044                 echoRequest, 
    3145                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/") 
    3246     
    33         rxResp = binding.Receive(echoResponseWrapper(),  
     47        response = binding.Receive(echoResponseWrapper(),  
    3448                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/") 
    3549 
     
    3852        sys.exit(1) 
    3953         
    40     if not isinstance(rxResp, echoResponse) and \ 
    41        not issubclass(echoResponse, rxResp.__class__): 
    42         print >>sys.stderr, "%s incorrect response type" % rxResp.__class__ 
     54    if not isinstance(response, echoResponse) and \ 
     55       not issubclass(echoResponse, response.__class__): 
     56        print >>sys.stderr, "%s incorrect response type" % response.__class__ 
    4357        sys.exit(1) 
    4458 
    45     print 'Response: %s' % rxResp._message 
     59    print 'Response: %s' % response._message 
    4660 
    4761 
  • TI12-security/trunk/python/Tests/xmlsec/WS-Security/wsInterface.py

    r1461 r1469  
     1"""WS-Security test SOAP interface definitions 
     2 
     3NERC Data Grid Project 
     4 
     5P J Kershaw 01/09/06 
     6 
     7Copyright (C) 2006 CCLRC & NERC 
     8 
     9This software may be distributed under the terms of the Q Public License, 
     10version 1.0 or later. 
     11""" 
     12 
     13reposID = '$Id$' 
     14 
    115import ZSI 
    216from ZSI import dispatch, TCcompound, TC 
    317from ZSI.TC import TypeDefinition, ElementDeclaration 
    418from ZSI.generate.pyclass import pyclass_type 
     19 
    520 
    621class echoRequest(TCcompound.Struct):  
     
    5873    def __init__( self, name=None, ns=None, **kw ): 
    5974        echoResponse.__init__(self, name='echoResponse', ns='urn:echoServer') 
    60  
    61  
    62 class SecurityHeaderType_Def(ZSI.TCcompound.ComplexType, TypeDefinition): 
    63     schema = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    64     type = (schema, "SecurityHeaderType") 
    65     def __init__(self, pname, ofwhat=(), attributes=None, extend=False, restrict=False, **kw): 
    66         ns = SecurityHeaderType_Def.schema 
    67         TClist = [ZSI.TC.AnyElement(aname="_any", minOccurs=0, maxOccurs="unbounded", nillable=False, processContents="lax")] 
    68         self.attribute_typecode_dict = attributes or {} 
    69         if extend: TClist += ofwhat 
    70         if restrict: TClist = ofwhat 
    71         else: 
    72             # attribute handling code 
    73             self.attribute_typecode_dict[("http://www.w3.org/2001/XMLSchema","anyAttribute")] = ZSI.TC.AnyElement() 
    74         ZSI.TCcompound.ComplexType.__init__(self, None, TClist, pname=pname, inorder=0, **kw) 
    75         class Holder: 
    76             __metaclass__ = pyclass_type 
    77             typecode = self 
    78             def __init__(self): 
    79                 # pyclass 
    80                 self._None = [] 
    81                 return 
    82         Holder.__name__ = "SecurityHeaderType_Holder" 
    83         self.pyclass = Holder 
    84  
    85  
    86 class Security_Dec(ElementDeclaration): 
    87     literal = "Security" 
    88     schema = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    89     def __init__(self, **kw): 
    90         kw["pname"] = ("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Security") 
    91         kw["aname"] = "_Security" 
    92         if SecurityHeaderType_Def not in Security_Dec.__bases__: 
    93             bases = list(Security_Dec.__bases__) 
    94             bases.insert(0, SecurityHeaderType_Def) 
    95             Security_Dec.__bases__ = tuple(bases) 
    96  
    97         SecurityHeaderType_Def.__init__(self, **kw) 
    98         if self.pyclass is not None: self.pyclass.__name__ = "Security_Dec_Holder" 
    99              
    100 class AttributedString_Def(TC.String, TypeDefinition): 
    101     # ComplexType/SimpleContent derivation of built-in type 
    102     schema = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    103     type = (schema, "AttributedString") 
    104     def __init__(self, pname, **kw): 
    105         if getattr(self, "attribute_typecode_dict", None) is None: self.attribute_typecode_dict = {} 
    106         # attribute handling code 
    107         self.attribute_typecode_dict[("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd","Id")] = TC.AnyType() 
    108         self.attribute_typecode_dict[("http://www.w3.org/2001/XMLSchema","anyAttribute")] = TC.AnyElement() 
    109         TC.String.__init__(self, pname, **kw) 
    110         class Holder(str): 
    111             __metaclass__ = pyclass_type 
    112             typecode = self 
    113         self.pyclass = Holder 
    114  
    115 class EncodedString_Def(TypeDefinition): 
    116     # ComplexType/SimpleContent derivation of user-defined type 
    117     schema = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    118     type = (schema, "EncodedString") 
    119     def __init__(self, pname, **kw): 
    120         ns = EncodedString_Def.schema 
    121         if AttributedString_Def not in EncodedString_Def.__bases__: 
    122             bases = list(EncodedString_Def.__bases__) 
    123             bases.insert(0, AttributedString_Def) 
    124             EncodedString_Def.__bases__ = tuple(bases) 
    125  
    126         if getattr(self, "attribute_typecode_dict", None) is None: self.attribute_typecode_dict = {} 
    127         # attribute handling code 
    128         self.attribute_typecode_dict["EncodingType"] = TC.URI() 
    129         AttributedString_Def.__init__(self, pname, **kw) 
    130  
    131  
    132 class BinarySecurityTokenType_Def(TypeDefinition): 
    133     # ComplexType/SimpleContent derivation of user-defined type 
    134     schema = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    135     type = (schema, "BinarySecurityTokenType") 
    136     def __init__(self, pname, **kw): 
    137         ns = BinarySecurityTokenType_Def.schema 
    138         if EncodedString_Def not in BinarySecurityTokenType_Def.__bases__: 
    139             bases = list(BinarySecurityTokenType_Def.__bases__) 
    140             bases.insert(0, EncodedString_Def) 
    141             BinarySecurityTokenType_Def.__bases__ = tuple(bases) 
    142  
    143         if getattr(self, "attribute_typecode_dict", None) is None: self.attribute_typecode_dict = {} 
    144         # attribute handling code 
    145         self.attribute_typecode_dict["ValueType"] = TC.URI() 
    146         EncodedString_Def.__init__(self, pname, **kw) 
    147          
    148 class BinarySecurityToken_Dec(ElementDeclaration): 
    149     literal = "BinarySecurityToken" 
    150     schema = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    151     def __init__(self, **kw): 
    152         kw["pname"] = ("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","BinarySecurityToken") 
    153         kw["aname"] = "_BinarySecurityToken" 
    154         if BinarySecurityTokenType_Def not in BinarySecurityToken_Dec.__bases__: 
    155             bases = list(BinarySecurityToken_Dec.__bases__) 
    156             bases.insert(0, BinarySecurityTokenType_Def) 
    157             BinarySecurityToken_Dec.__bases__ = tuple(bases) 
    158  
    159         BinarySecurityTokenType_Def.__init__(self, **kw) 
    160         if self.pyclass is not None: self.pyclass.__name__ = "BinarySecurityToken_Dec_Holder" 
  • 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       
  • TI12-security/trunk/python/Tests/xmlsec/WS-Security/wsServer.py

    r1465 r1469  
    11#!/usr/bin/env python 
     2 
     3"""WS-Security test server 
     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 sys 
     
    166180    httpd.rpc = rpc 
    167181    httpd.serve_forever() 
    168      
    169      
    170182 
    171 ''' 
    172 def echo(ps): 
    173     frame = sys._getframe().f_back 
    174     import pdb;pdb.set_trace() 
    175 #    response._message = message.Parse(TC.Any('echo', aslist=0))[0] 
    176     request = ps.Parse(echoRequestWrapper) 
    177     response = echoResponseWrapper()     
    178     response._message = request._message 
    179      
    180     return response 
    181 ''' 
    182183 
    183184if __name__ == '__main__': 
Note: See TracChangeset for help on using the changeset viewer.