Changeset 3687 for TI12-security


Ignore:
Timestamp:
26/03/08 16:46:50 (12 years ago)
Author:
pjkersha
Message:

wsSecurity.SignatureHandler?: added support for SignatureConfirmation? as of WSSE 1.1 spec. Continuing testing vs. Axis2 Rampart client.

Location:
TI12-security/trunk/python
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/wsSecurity.py

    r3676 r3687  
    3030 
    3131import ZSI 
    32 from ZSI.wstools.Namespaces import DSIG, ENCRYPTION, OASIS, WSU, WSA200403, \ 
     32from ZSI.wstools.Namespaces import DSIG, ENCRYPTION, WSU, WSA200403, \ 
    3333                                   SOAP, SCHEMA # last included for xsi 
    34                                     
     34 
     35from ZSI.wstools.Namespaces import OASIS as _OASIS 
     36                                   
    3537from ZSI.TC import ElementDeclaration,TypeDefinition 
    3638from ZSI.generate.pyclass import pyclass_type 
     
    6971    #UTILITY = "http://schemas.xmlsoap.org/ws/2003/06/utility" 
    7072    UTILITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
    71      
     73 
     74class OASIS(_OASIS): 
     75    WSSE11 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.1.xsd" 
     76        
    7277def getElements(node, nameList): 
    7378    '''DOM Helper function for getting child elements from a given node''' 
     
    119124    WS-Security 
    120125     
    121     @type __beginCert: string 
    122     @param __beginCert: delimiter for beginning of base64 encoded portion of 
    123     a PEM encoded X.509 certificate 
    124     @type __endCert: string 
    125     @cvar: __endCert: equivalent end delimiter 
    126      
    127     @type __x509CertPat: regular expression pattern object 
    128     @cvar __x509CertPat: regular expression for extracting the base64 encoded  
    129     portion of a PEM encoded X.509 certificate 
    130126    @cvar binSecTokValType: supported ValueTypes for BinarySecurityToken 
    131127    element in WSSE header 
    132     @type binSecTokValType: dict""" 
     128    @type binSecTokValType: dict 
    133129     
    134     __beginCert = '-----BEGIN CERTIFICATE-----\n' 
    135     __endCert = '\n-----END CERTIFICATE-----' 
    136     __x509CertPat = re.compile(__beginCert + \ 
    137                                '?(.*?)\n?-----END CERTIFICATE-----', 
    138                                re.S) 
     130    @ivar addTimestamp: set to true to add a timestamp to outbound messages 
     131    @type addTimestamp: bool  
     132 
     133    @ivar applySignatureConfirmation: for servers - set this flag to enable the  
     134    signature value of a request to be recorded and included with a  
     135    SignatureConfirmation element in the response. 
     136    @type applySignatureConfirmation: bool 
     137     
     138    @param b64EncSignatureValue: base 64 encoded signature value for the last  
     139    message verified 
     140    @type b64EncSignatureValue: string/None""" 
     141 
    139142     
    140143    binSecTokValType = { 
     
    143146        "X509v3":        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" 
    144147    } 
    145      
     148 
     149 
    146150    #_________________________________________________________________________ 
    147151    def __init__(self, 
     
    158162                 caCertFilePathList=[], 
    159163                 addTimestamp=True, 
     164                 applySignatureConfirmation=False, 
    160165                 refC14nKw={'unsuppressedPrefixes': ['xmlns',  
    161166                                                     'xsi',  
     
    236241        @type addTimestamp: bool  
    237242         
     243        @param : for servers - set this flag to enable the signature value of a 
     244        request to be recorded and included with a SignatureConfirmation  
     245        element in the response. 
     246        @type : bool  
     247         
    238248        @param refC14nKw: dictionary of keywords to reference  
    239249        Canonicalization.  Use 'unsuppressedPrefixes' keyword to set  
     
    284294             
    285295        self.addTimestamp = addTimestamp 
    286          
     296        self.applySignatureConfirmation = applySignatureConfirmation 
     297        self.b64EncSignatureValue = None 
    287298                 
    288299    #_________________________________________________________________________ 
     
    651662                      doc="List of CA cert. files used for verification") 
    652663                 
    653          
     664 
     665    def _applySignatureConfirmation(self, wsseElem): 
     666        '''Add SignatureConfirmation element - as specified in WS-Security 1.1 
     667        - to outbound message on receipt of a signed message from a client 
     668         
     669        This has been added in through tests vs. Apache Axis Rampart client 
     670         
     671        @type wsseElem:  
     672        @param wsseElem: wsse:Security element''' 
     673        if self.b64EncSignatureValue is None: 
     674            log.info(\ 
     675"SignatureConfirmation element requested but no request signature was cached") 
     676            return 
     677         
     678        sigConfirmElem = wsseElem.createAppendElement(OASIS.WSSE11,  
     679                                                      'SignatureConfirmation') 
     680         
     681        # Add ID so that the element can be included in the signature 
     682        sigConfirmElem.node.setAttribute('wsu:Id', "signatureConfirmation") 
     683 
     684        # Add ID so that the element can be included in the signature 
     685        # Following line is a hck to avoid appearance of #x when serialising \n 
     686        # chars TODO: why is this happening?? 
     687        b64EncSignatureValue = ''.join(self.b64EncSignatureValue.split('\n')) 
     688        sigConfirmElem.node.setAttribute('Value', b64EncSignatureValue) 
     689         
     690         
     691    def _addTimeStamp(self, wsseElem, elapsedSec=60*5): 
     692        '''Add a timestamp to wsse:Security section of message to be signed 
     693        e.g. 
     694            <wsu:Timestamp wsu:Id="timestamp"> 
     695               <wsu:Created>2008-03-25T14:40:37.319Z</wsu:Created> 
     696               <wsu:Expires>2008-03-25T14:45:37.319Z</wsu:Expires> 
     697            </wsu:Timestamp> 
     698         
     699        @type wsseElem:  
     700        @param wsseElem: wsse:Security element 
     701        @type elapsedSec: int     
     702        @param elapsedSec: time interval in seconds between Created and Expires 
     703        time stamp values  
     704        ''' 
     705        # Nb. wsu ns declaration is in the SOAP header elem 
     706        timestampElem = wsseElem.createAppendElement(_WSU.UTILITY, 'Timestamp') 
     707 
     708        # Add ID so that the timestamp element can be included in the signature 
     709        timestampElem.node.setAttribute('wsu:Id', "timestamp") 
     710         
     711        # Value type can be any be any one of those supported via  
     712        # binSecTokValType 
     713        createdElem = timestampElem.createAppendElement(_WSU.UTILITY,'Created') 
     714        dtCreatedTime = datetime.utcnow() 
     715        createdElem.createAppendTextNode(dtCreatedTime.isoformat('T')+'Z') 
     716         
     717        dtExpiryTime = dtCreatedTime + timedelta(seconds=elapsedSec) 
     718        expiresElem = timestampElem.createAppendElement(_WSU.UTILITY,'Expires') 
     719        expiresElem.createAppendTextNode(dtExpiryTime.isoformat('T')+'Z') 
     720         
     721 
     722    def _verifyTimeStamp(self, parsedSOAP, ctxt): 
     723        """Call from verify to check timestamp if found.   
     724         
     725        TODO: refactor input args - maybe these should by object attributes 
     726         
     727        @type parsedSOAP: ZSI.parse.ParsedSoap 
     728        @param parsedSOAP: object contain parsed SOAP message received from 
     729        sender 
     730        @type ctxt: 
     731        @param ctxt: XPath context object""" 
     732 
     733        try: 
     734            timestampNode = xpath.Evaluate('//wsse:Timestamp', 
     735                                           contextNode=parsedSOAP.dom, 
     736                                           context=ctxt)[0] 
     737        except: 
     738            log.warning("Verifying message - No timestamp element found") 
     739            return 
     740         
     741        # Time now  
     742        dtNow = datetime.utcnow() 
     743         
     744        createdNode = timestampNode.getElementsByTagName("Created") 
     745         
     746        # Workaround for fractions of second 
     747        try: 
     748            [createdDateTime, createdSecFraction]=createdNode.nodeValue.split() 
     749        except ValueError, e: 
     750            raise ValueError("Parsing timestamp Created element: %s" % e) 
     751         
     752        dtCreated = datetime.strptime(createdDateTime, '%Y-%m-%dT%H:%M:%S') 
     753        dtCreated += timedelta(seconds=int(createdSecFraction)) 
     754        if dtCreated >= dtNow: 
     755            raise TimestampError(\ 
     756        "Timestamp created time %s is equal to or after the current time %s" %\ 
     757                (dtCreated, dtNow)) 
     758         
     759        expiresNode = timestampNode.getElementsByTagName("Expires") 
     760        if expiresNode is None: 
     761            log.warning(\ 
     762                "Verifying message - No Expires element found in Timestamp") 
     763            return 
     764 
     765        try: 
     766            [expiresDateTime, expiresSecFraction]=expiresNode.nodeValue.split() 
     767        except ValueError, e: 
     768            raise ValueError("Parsing timestamp Expires element: %s" % e) 
     769         
     770        dtCreated = datetime.strptime(expiresDateTime, '%Y-%m-%dT%H:%M:%S') 
     771        dtCreated += timedelta(seconds=int(createdSecFraction)) 
     772        if dtExpiry > dtNow: 
     773            raise TimestampError(\ 
     774                "Timestamp expiry time %s is after the current time %s" % \ 
     775                (dtCreated, dtNow)) 
     776             
     777                    
    654778    #_________________________________________________________________________ 
    655779    def sign(self, soapWriter): 
     
    677801 
    678802        soapWriter._header.setNamespaceAttribute('wsse', OASIS.WSSE) 
     803        soapWriter._header.setNamespaceAttribute('wsse11', OASIS.WSSE11) 
    679804        soapWriter._header.setNamespaceAttribute('wsu', _WSU.UTILITY) 
    680805        soapWriter._header.setNamespaceAttribute('ds', DSIG.BASE) 
     
    704829        # Add WSSE element 
    705830        wsseElem = soapWriter._header.createAppendElement(OASIS.WSSE,  
    706                                                          'Security') 
     831                                                          'Security') 
    707832        wsseElem.setNamespaceAttribute('wsse', OASIS.WSSE) 
    708833         
     
    734859            self._addTimeStamp(wsseElem) 
    735860             
    736              
     861        # Signature Confirmation 
     862        if self.applySignatureConfirmation:  
     863            self._applySignatureConfirmation(wsseElem) 
     864         
    737865        # Signature 
    738866        signatureElem = wsseElem.createAppendElement(DSIG.BASE, 'Signature') 
     
    786914        # canonicalization based on soapWriter.dom.node seems to give an 
    787915        # error: the order of wsu:Id attribute is not correct 
    788         docNode = Reader().fromString(str(soapWriter)) 
     916        try: 
     917            docNode = Reader().fromString(str(soapWriter)) 
     918        except Exception, e: 
     919            raise SignatureError("Error parsing SOAP message for signing: %s"%\ 
     920                                 e) 
     921 
    789922        ctxt = Context(docNode, processorNss=processorNss) 
    790923        refNodes = xpath.Evaluate('//*[@wsu:Id]',  
     
    807940#            refC14n = Canonicalize(refNode, **self.__refC14nKw) 
    808941             
    809             #refNode.prefix = 'soapenv' 
    810942            refSubsetList = getChildNodes(refNode) 
    811943            refC14n = Canonicalize(docNode,  
     
    8861018        signatureValueElem.createAppendTextNode(b64EncSignatureValue) 
    8871019 
    888     def _addTimeStamp(self, wsseElem, elapsedSec=60*5): 
    889         '''Add a timestamp to wsse:Security section of message to be signed 
    890         e.g. 
    891             <wsu:Timestamp wsu:Id="timestamp"> 
    892                <wsu:Created>2008-03-25T14:40:37.319Z</wsu:Created> 
    893                <wsu:Expires>2008-03-25T14:45:37.319Z</wsu:Expires> 
    894             </wsu:Timestamp> 
    895         ''' 
    896         # Nb. wsu ns declaration is in the SOAP header elem 
    897         timestampElem = wsseElem.createAppendElement(_WSU.UTILITY, 'Timestamp') 
    898  
    899         # Add ID so that the timestamp element can be included in the signature 
    900         timestampElem.node.setAttribute('wsu:Id', "timestamp") 
    901          
    902         # Value type can be any be any one of those supported via  
    903         # binSecTokValType 
    904         createdElem = timestampElem.createAppendElement(_WSU.UTILITY,'Created') 
    905         dtCreatedTime = datetime.utcnow() 
    906         createdElem.createAppendTextNode(dtCreatedTime.isoformat('T')+'Z') 
    907          
    908         dtExpiryTime = dtCreatedTime + timedelta(seconds=elapsedSec) 
    909         expiresElem = timestampElem.createAppendElement(_WSU.UTILITY,'Expires') 
    910         expiresElem.createAppendTextNode(dtExpiryTime.isoformat('T')+'Z') 
    911          
    912  
    913     def _verifyTimeStamp(self, parsedSOAP, ctxt): 
    914         """Call from verify to check timestamp if found.   
    915          
    916         TODO: refactor input args - maybe these should by object attributes 
    917          
    918         @type parsedSOAP: ZSI.parse.ParsedSoap 
    919         @param parsedSOAP: object contain parsed SOAP message received from 
    920         sender 
    921         @type ctxt: 
    922         @param ctxt: XPath context object""" 
    923  
    924         try: 
    925             timestampNode = xpath.Evaluate('//wsse:Timestamp', 
    926                                            contextNode=parsedSOAP.dom, 
    927                                            context=ctxt)[0] 
    928         except: 
    929             log.warning("Verifying message - No timestamp element found") 
    930             return 
    931          
    932         # Time now  
    933         dtNow = datetime.utcnow() 
    934          
    935         createdNode = timestampNode.getElementsByTagName("Created") 
    936          
    937         # Workaround for fractions of second 
    938         try: 
    939             [createdDateTime, createdSecFraction]=createdNode.nodeValue.split() 
    940         except ValueError, e: 
    941             raise ValueError("Parsing timestamp Created element: %s" % e) 
    942          
    943         dtCreated = datetime.strptime(createdDateTime, '%Y-%m-%dT%H:%M:%S') 
    944         dtCreated += timedelta(seconds=int(createdSecFraction)) 
    945         if dtCreated >= dtNow: 
    946             raise TimestampError(\ 
    947         "Timestamp created time %s is equal to or after the current time %s" %\ 
    948                 (dtCreated, dtNow)) 
    949          
    950         expiresNode = timestampNode.getElementsByTagName("Expires") 
    951         if expiresNode is None: 
    952             log.warning(\ 
    953                 "Verifying message - No Expires element found in Timestamp") 
    954             return 
    955  
    956         try: 
    957             [expiresDateTime, expiresSecFraction]=expiresNode.nodeValue.split() 
    958         except ValueError, e: 
    959             raise ValueError("Parsing timestamp Expires element: %s" % e) 
    960          
    961         dtCreated = datetime.strptime(expiresDateTime, '%Y-%m-%dT%H:%M:%S') 
    962         dtCreated += timedelta(seconds=int(createdSecFraction)) 
    963         if dtExpiry > dtNow: 
    964             raise TimestampError(\ 
    965                 "Timestamp expiry time %s is after the current time %s" % \ 
    966                 (dtCreated, dtNow)) 
     1020        log.info("Signature generation complete") 
    9671021 
    9681022 
     
    11281182        # This line necessary? - only decode call needed??  pyGridWare vers 
    11291183        # seems to preserve whitespace 
    1130         b64EncSignatureValue = \ 
    1131                     str(signatureValueNode.childNodes[0].nodeValue).strip() 
    1132          
     1184#        b64EncSignatureValue = \ 
     1185#                    str(signatureValueNode.childNodes[0].nodeValue).strip() 
     1186        b64EncSignatureValue = signatureValueNode.childNodes[0].nodeValue 
    11331187        signatureValue = base64.decodestring(b64EncSignatureValue) 
    11341188 
    1135  
     1189        # Cache Signature Value here so that a response can include it 
     1190        if self.applySignatureConfirmation: 
     1191            # re-encode string to avoid possible problems with interpretation  
     1192            # of line breaks 
     1193            self.b64EncSignatureValue = b64EncSignatureValue 
     1194        else: 
     1195            self.b64EncSignatureValue = None 
     1196          
    11361197        # Look for X.509 Cert in wsse:BinarySecurityToken node 
    11371198        try: 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/wsSecurity/server/echoServer.py

    r3652 r3687  
    108108                                signingPriKeyPwd=signingPriKeyPwd, 
    109109                                caCertFilePathList=caCertFilePathList, 
     110                                applySignatureConfirmation=True, 
    110111                                refC14nKw={'unsuppressedPrefixes':[]}, 
    111112                                signedInfoC14nKw={'unsuppressedPrefixes':[]}) 
Note: See TracChangeset for help on using the changeset viewer.