Changeset 1465


Ignore:
Timestamp:
30/08/06 16:36:23 (13 years ago)
Author:
pjkersha
Message:

Added sign and verify to wsServer but problems with canonicalization causing verify error. This seems to be
due to attribute order differences. These shouldn't happen given the same canonicalization method for
signature and verification but the could be a problem with the way that the DOM code creates the nodes in
sign() ?

sing was added to server side code by overriding SOAPRequestHandler.do_POST and making a custom _Dispatch
function.

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

Legend:

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

    r1454 r1465  
    11#!/usr/bin/env python 
    22 
     3import sys, socket 
    34from ZSI import Binding, TCcompound, TC 
    45from wsInterface import * 
     
    2324    import pdb;pdb.set_trace() 
    2425    print ' Sending: %s' % MESSAGE 
    25     txResp = binding.Send(None,  
     26     
     27    try: 
     28        txResp = binding.Send(None,  
    2629                 'echo',  
    2730                 echoRequest, 
    2831                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/") 
    2932     
    30     rxResp = binding.Receive(echoResponseWrapper(),  
    31                     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/") 
    32      
     33        rxResp = binding.Receive(echoResponseWrapper(),  
     34                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/") 
     35 
     36    except socket.error, (errNum, errMsg): 
     37        print >>sys.stderr, "Socket error: %s" % errMsg 
     38        sys.exit(1) 
     39         
    3340    if not isinstance(rxResp, echoResponse) and \ 
    3441       not issubclass(echoResponse, rxResp.__class__): 
    35         raise TypeError, "%s incorrect response type" % rxResp.__class__ 
     42        print >>sys.stderr, "%s incorrect response type" % rxResp.__class__ 
     43        sys.exit(1) 
    3644 
    3745    print 'Response: %s' % rxResp._message 
  • TI12-security/trunk/python/Tests/xmlsec/WS-Security/wsSecurity.py

    r1461 r1465  
    1616from ZSI.generate.pyclass import pyclass_type 
    1717 
     18from ZSI.wstools.Utility import DOMException, SplitQName 
     19from ZSI.wstools.Utility import NamespaceError, MessageInterface, ElementProxy 
     20 
    1821# XML Parsing 
    1922from cStringIO import StringIO 
     
    2427from ZSI.wstools.c14n import Canonicalize 
    2528from xml.dom import Node 
     29from xml.xpath.Context import Context 
     30from xml import xpath 
    2631 
    2732# Type codes for signature elements 
     
    6469 
    6570    def sign(self, soapWriter): 
    66  
    67         # Use wsse:TransformationParameters with ds:Transforms?? 
    68         msgTmpl = """<?xml version="1.0" encoding="UTF-8"?> 
    69 <!-- 
    70 SOAP Message with WSSE Signature 
    71 --> 
    72 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  
    73         xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing"  
    74         xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
    75         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    76     <soapenv:Header> 
    77         <wsse:Security  
    78                 xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext"  
    79                 xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"  
    80                 soapenv:mustUnderstand="1"> 
    81             <wsse:BinarySecurityToken 
    82                 wsu:Id="binaryToken" 
    83                 ValueType="wsse:X509v3" 
    84                 EncodingType="wsse:Base64Binary"> 
    85 %s 
    86             </wsse:BinarySecurityToken> 
    87             <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 
    88                 <ds:SignedInfo> 
    89                     <ds:CanonicalizationMethod  
    90                     Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
    91                     <ds:SignatureMethod  
    92                     Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
    93                 </ds:SignedInfo> 
    94                 <ds:SignatureValue>%s</ds:SignatureValue> 
    95                 <ds:KeyInfo> 
    96                     <wsse:SecurityTokenReference> 
    97                         <wsse:Reference URI="#binaryToken"/> 
    98                     </wsse:SecurityTokenReference> 
    99                 </ds:KeyInfo> 
    100             </ds:Signature> 
    101         </wsse:Security> 
    102     </soapenv:Header> 
    103     <soapenv:Body xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"  
    104             wsu:Id="body"> 
    105     Hello, World! 
    106     </soapenv:Body> 
    107 </soapenv:Envelope>""" 
    108  
    109  
     71        '''Sign the message body and binary security token of a SOAP message 
     72        ''' 
    11073        # Add X.509 cert as binary security token 
    11174        x509Cert = X509.load_cert(self.__certFilePath) 
     
    11679        x509CertStr = x509CertPat.findall(x509Cert.as_pem())[0] 
    11780 
    118 #        attrTypeCodeDict = \ 
    119 #        { 
    120 #            (OASIS.UTILITY, 'Id'):  ZSI.TC.String(), 
    121 #            'ValueType':            ZSI.TC.String(), 
    122 #            'EncodingType':         ZSI.TC.String() 
    123 #        } 
    124 #        binSecurityTokTC = \ 
    125 #                getGlobalElemDecl(OASIS.WSSE, "BinarySecurityToken") 
    126 # 
    127 #        binSecurityTokTC.attribute_typecode_dict.update(attrTypeCodeDict) 
    128 #         
    129 #        securityTC = getGlobalElemDecl(OASIS.WSSE, "Security") 
    130 #        securityPyObj = securityTC.pyclass() 
    131 #        securityPyObj._any = [] 
    132 #        securityPyObj._any.append(binSecurityTokTC.pyclass())    
    133 #         
    134         #soapWriter.serialize_header(securityPyObj, securityTC) 
    13581         
    13682        # Namespaces for XPath searches 
     
    156102        binSecTokElem.node.setAttribute('ValueType', "wsse:X509v3") 
    157103        binSecTokElem.node.setAttribute('EncodingType', "wsse:Base64Binary") 
    158         binSecTokElem.createAppendTextNode(x509CertStr) 
    159104         
    160105        # Add ID 
    161106        binSecTokElem.node.setAttribute('wsu:Id', "binaryToken") 
     107 
     108        binSecTokElem.createAppendTextNode(x509CertStr) 
     109 
    162110         
    163111        signatureElem = wsseElem.createAppendElement(DSIG.BASE, 'Signature') 
     
    181129        soapWriter.body.node.setAttribute('xmlns:wsu', WSU.UTILITY) 
    182130         
     131         
    183132        # 1) Reference Generation 
    184133        # 
    185134        # Find references 
    186135        #idNodes = XPath.Compile('//*[@wsu:Id]').evaluate(docCtxt) 
    187         idElems = [binSecTokElem, soapWriter.body] 
     136        idElems = [soapWriter.body]#[binSecTokElem, soapWriter.body] 
    188137        for idElem in idElems: 
    189138             
     
    192141             
    193142            # Canonicalize reference 
    194             c14nRef = idElem.canonicalize() 
     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 
    195151             
    196152            # Calculate digest for reference and base 64 encode 
     
    199155            digestValue = base64.encodestring(sha(c14nRef).digest()).strip() 
    200156 
     157 
    201158            # Add a new reference element to SignedInfo 
    202159            refElem = signedInfoElem.createAppendElement(DSIG.BASE,  
    203160                                                         'Reference') 
    204161            refElem.node.setAttribute('URI', uri) 
    205             refElem.createAppendTextNode(digestValue) 
     162             
     163            # Use ds:Transforms or wsse:TransformationParameters? 
     164            tranformsElem = refElem.createAppendElement(DSIG.BASE,  
     165                                                        'Transforms') 
     166            tranformElem = tranformsElem.createAppendElement(DSIG.BASE,  
     167                                                             'Transform') 
     168            tranformElem.node.setAttribute('Algorithm', DSIG.C14N) 
     169             
     170            refElem.createAppendElement(DSIG.BASE, 'DigestMethod') 
     171            refElem.node.setAttribute('Algorithm', DSIG.DIGEST_SHA1) 
     172             
     173            digestValueElem = refElem.createAppendElement(DSIG.BASE,  
     174                                                          'DigestValue') 
     175            digestValueElem.createAppendTextNode(digestValue) 
    206176 
    207177        
     
    249219         
    250220        # Check the signature  
    251         verify = bool(rsaPubKey.verify(signedInfoDigestValue, signatureValue)) 
    252         print soapWriter.dom.node.toprettyxml() 
    253          
    254         from xml.dom.ext.reader.PyExpat import Reader 
    255         Reader().fromString(str(soapWriter)) 
    256         import pdb;pdb.set_trace()         
    257  
    258  
    259     def verify(self, soapWriter): 
     221#        verify = bool(rsaPubKey.verify(signedInfoDigestValue, signatureValue)) 
     222#        print soapWriter.dom.node.toprettyxml() 
     223#         
     224#        from xml.dom.ext.reader.PyExpat import Reader 
     225#        Reader().fromString(str(soapWriter)) 
     226#        import pdb;pdb.set_trace()         
     227 
     228 
     229    def verify(self, parsedSOAP): 
    260230        """Verify signature""" 
    261         import pdb;pdb.set_trace() 
    262         return 
    263         # Parse file 
    264         doc = NonvalidatingReader.parseStream(StringIO(xmlTxt)) 
    265          
    266         # Set namespaces for XPath queries 
     231         
     232        element = ElementProxy(None, message=parsedSOAP.header) 
    267233        processorNss = \ 
    268234        { 
     
    270236            'wsu':    WSU.UTILITY,  
    271237            'wsse':   OASIS.WSSE,  
    272             'wsa':    WSA200403.ADDRESS, 
    273238            'soapenv':"http://schemas.xmlsoap.org/soap/envelope/"  
    274239        } 
    275         docCtxt = XPath.Context.Context(doc, processorNss=processorNss) 
    276          
    277         # Two stagfe process: reference validation followed by signature  
     240        ctxt = Context(parsedSOAP.dom, processorNss=processorNss) 
     241         
     242 
     243        signatureNodes = xpath.Evaluate('//ds:Signature',  
     244                                        contextNode=parsedSOAP.dom,  
     245                                        context=ctxt) 
     246        if len(signatureNodes) > 1: 
     247            raise Exception, 'Multiple ds:Signature elements found' 
     248         
     249        try: 
     250            signatureNodes = signatureNodes[0] 
     251        except: 
     252            # Message wasn't signed 
     253            return 
     254         
     255        # Two stage process: reference validation followed by signature  
    278256        # validation  
    279257         
    280258        # 1) Reference Validation        
    281         refNodes = XPath.Compile('//ds:Reference').evaluate(docCtxt) 
    282              
     259        refNodes = xpath.Evaluate('//ds:Reference',  
     260                                  contextNode=parsedSOAP.dom,  
     261                                  context=ctxt) 
     262            
    283263        # Make a lambda to pick out node child or children with a given  
    284264        # name 
     
    316296            # XPath reference 
    317297            uriXPath = '//*[@wsu:Id="%s"]' % refURI[1:] 
    318             uriNode = XPath.Compile(uriXPath).evaluate(docCtxt)[0] 
     298            uriNode = xpath.Evaluate(uriXPath,  
     299                                     contextNode=parsedSOAP.dom,  
     300                                     context=ctxt)[0] 
    319301 
    320302            c14nRef = Canonicalize(uriNode, **kw) 
     303            import pdb;pdb.set_trace() 
    321304            digestValue = base64.encodestring(sha(c14nRef).digest()).strip() 
    322305             
     
    327310            # Reference validates if the two digest values are the same 
    328311            if digestValue != nodeDigestValue: 
    329                 raise Exception, "DigestValues do not match: URI=%s" % uri 
    330          
    331          
     312                raise Exception, 'Digest Values do not match for URI: "%s"' %\ 
     313                                                                        refURI 
     314                 
    332315        # 2) Signature Validation 
    333         signedInfoNode = XPath.Compile('//ds:SignedInfo').evaluate(docCtxt)[0] 
     316        signedInfoNode = xpath.Evaluate('//ds:SignedInfo', 
     317                                        contextNode=parsedSOAP.dom,  
     318                                        context=ctxt)[0] 
    334319 
    335320        # Get the canonicalization method - change later to check this and 
     
    349334        # Get the signature value in order to check against the digest just 
    350335        # calculated 
    351         signatureValueNode = \ 
    352                     XPath.Compile('//ds:SignatureValue').evaluate(docCtxt)[0] 
     336        signatureValueNode = xpath.Evaluate('//ds:SignatureValue', 
     337                                            contextNode=parsedSOAP.dom,  
     338                                            context=ctxt)[0] 
    353339 
    354340        # Remove base 64 encoding 
     
    371357                                           signatureValue)) 
    372358        except RSA.RSAError: 
    373             verify = False 
    374              
    375         return verify 
     359            raise Exception, "Invalid Signature" 
    376360 
    377361 
  • TI12-security/trunk/python/Tests/xmlsec/WS-Security/wsServer.py

    r1461 r1465  
    22 
    33import sys 
     4import socket 
     5 
     6# Web service interface 
     7from ZSI import * 
     8from ZSI.dispatch import SOAPRequestHandler, _client_binding 
     9from ZSI.auth import _auth_tc, AUTH, ClientBinding 
     10 
     11from BaseHTTPServer import HTTPServer 
     12 
     13from wsSecurity import * 
    414from wsInterface import * 
    515 
    616 
     17#_________________________________________________________________________ 
     18def echo(ps): 
     19    """example service simply returns message sent to it""" 
     20    
     21    import pdb;pdb.set_trace() 
     22    signatureHandler = SignatureHandler(\ 
     23                            certFilePath='../../Junk-cert.pem', 
     24                            priKeyFilePath='../../Junk-key.pem', 
     25                            priKeyPwd=open('../../tmp2').read().strip()) 
     26    signatureHandler.verify(ps) 
     27 
     28    request = ps.Parse(echoRequestWrapper) 
     29    response = echoResponseWrapper()     
     30    response._message = request._message 
     31     
     32    return response 
     33 
     34def _Dispatch(ps, modules, SendResponse, SendFault, docstyle=0, 
     35              nsdict={}, typesmodule=None, rpc=None, **kw): 
     36    '''Find a handler for the SOAP request in ps; search modules. 
     37    Call SendResponse or SendFault to send the reply back, appropriately. 
     38 
     39    Default Behavior -- Use "handler" method to parse request, and return 
     40       a self-describing request (w/typecode). 
     41 
     42    Other Behaviors: 
     43        docstyle -- Parse result into an XML typecode (DOM). Behavior, wrap result  
     44          in a body_root "Response" appended message. 
     45 
     46        rpc -- Specify RPC wrapper of result. Behavior, ignore body root (RPC Wrapper) 
     47           of request, parse all "parts" of message via individual typecodes.  Expect 
     48           response pyobj w/typecode to represent the entire message (w/RPC Wrapper), 
     49           else pyobj w/o typecode only represents "parts" of message. 
     50 
     51    ''' 
     52    global _client_binding 
     53    try: 
     54        what = ps.body_root.localName 
     55 
     56        # See what modules have the element name. 
     57        if modules is None: 
     58            modules = ( sys.modules['__main__'], ) 
     59 
     60        handlers = [ getattr(m, what) for m in modules if hasattr(m, what) ] 
     61        if len(handlers) == 0: 
     62            raise TypeError("Unknown method " + what) 
     63 
     64        # Of those modules, see who's callable. 
     65        handlers = [ h for h in handlers if callable(h) ] 
     66        if len(handlers) == 0: 
     67            raise TypeError("Unimplemented method " + what) 
     68        if len(handlers) > 1: 
     69            raise TypeError("Multiple implementations found: " + `handlers`) 
     70        handler = handlers[0] 
     71 
     72        _client_binding = ClientBinding(ps) 
     73        if docstyle: 
     74            result = handler(ps.body_root) 
     75            tc = TC.XML(aslist=1, pname=what + 'Response') 
     76        elif rpc is None: 
     77            # Not using typesmodule, expect  
     78            # result to carry typecode 
     79            result = handler(ps) 
     80            if hasattr(result, 'typecode') is False: 
     81                raise TypeError("Expecting typecode in result") 
     82            tc = result.typecode 
     83        else: 
     84            data = _child_elements(ps.body_root) 
     85            if len(data) == 0: 
     86                arg = [] 
     87            else: 
     88                try: 
     89                    try: 
     90                        type = data[0].localName 
     91                        tc = getattr(typesmodule, type).typecode 
     92                    except Exception, e: 
     93                        tc = TC.Any() 
     94                    arg = [ tc.parse(e, ps) for e in data ] 
     95                except EvaluateException, e: 
     96                    SendFault(FaultFromZSIException(e), **kw) 
     97                    return 
     98            result = handler(*arg) 
     99            if hasattr(result, 'typecode'): 
     100                tc = result.typecode 
     101            else: 
     102                tc = TC.Any(aslist=1, pname=what + 'Response') 
     103                result = [ result ] 
     104 
     105                 
     106        sw = SoapWriter(nsdict=nsdict) 
     107         
     108        sw.serialize(result, tc, rpc=rpc) 
     109                 
     110        signatureHandler = SignatureHandler(\ 
     111                                certFilePath='../../Junk-cert.pem', 
     112                                priKeyFilePath='../../Junk-key.pem', 
     113                                priKeyPwd=open('../../tmp2').read().strip()) 
     114        signatureHandler.sign(sw) 
     115         
     116        return SendResponse(str(sw), **kw) 
     117     
     118    except Exception, e: 
     119        # Something went wrong, send a fault. 
     120        return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) 
     121 
     122#_____________________________________________________________________________ 
     123class EchoSOAPRequestHandler(SOAPRequestHandler): 
     124    """Implement to allow overloaded do_POST in order to handle WS-Security 
     125    for outbound messages""" 
     126  
     127    def do_POST(self): 
     128        """Override default to allow custom dispatch call""" 
     129        try: 
     130            ct = self.headers['content-type'] 
     131            if ct.startswith('multipart/'): 
     132                cid = resolvers.MIMEResolver(ct, self.rfile) 
     133                xml = cid.GetSOAPPart() 
     134                ps = ParsedSoap(xml, resolver=cid.Resolve) 
     135            else: 
     136                length = int(self.headers['content-length']) 
     137                ps = ParsedSoap(self.rfile.read(length)) 
     138        except ParseException, e: 
     139            self.send_fault(FaultFromZSIException(e)) 
     140            return 
     141        except Exception, e: 
     142            # Faulted while processing; assume it's in the header. 
     143            self.send_fault(FaultFromException(e, 1, sys.exc_info()[2])) 
     144            return 
     145         
     146        _Dispatch(ps, self.server.modules, self.send_xml, self.send_fault, 
     147                  docstyle=self.server.docstyle, nsdict=self.server.nsdict, 
     148                  typesmodule=self.server.typesmodule, rpc=self.server.rpc) 
     149 
     150 
     151#_____________________________________________________________________________ 
     152def AsServer(port=80,  
     153             modules=None,  
     154             docstyle=0,  
     155             nsdict={},  
     156             typesmodule=None, 
     157             rpc=None, 
     158             **kw): 
     159     
     160    address = ('', port) 
     161    httpd = HTTPServer(address, EchoSOAPRequestHandler) 
     162    httpd.modules = modules 
     163    httpd.docstyle = docstyle 
     164    httpd.nsdict = nsdict 
     165    httpd.typesmodule = typesmodule 
     166    httpd.rpc = rpc 
     167    httpd.serve_forever() 
     168     
     169     
     170 
     171''' 
    7172def echo(ps): 
    8173    frame = sys._getframe().f_back 
     
    14179     
    15180    return response 
    16  
     181''' 
    17182 
    18183if __name__ == '__main__': 
    19184    print "Server listening ..." 
     185 
    20186    try: 
    21         dispatch.AsServer(port=8080) 
    22          
     187        AsServer(port=8080) 
     188 
    23189    except KeyboardInterrupt: 
    24190        sys.exit(0) 
     191 
     192    except socket.error, e: 
     193        print >>sys.stderr, "Server socket error: %s" % e[1] 
     194        sys.exit(1) 
     195 
     196#    except Exception, e: 
     197#        print >>sys.stderr, "Server: %s" % e 
     198#        sys.exit(1) 
Note: See TracChangeset for help on using the changeset viewer.