Changeset 4038 for TI12-security/trunk
- Timestamp:
- 10/07/08 15:45:22 (11 years ago)
- 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 13 13 14 14 from ConfigParser import SafeConfigParser 15 from ndg.security.common.wssecurity.etree import SignatureHandler 15 from ndg.security.common.wssecurity.etree import SignatureHandler, \ 16 NoSignatureFound 16 17 17 18 from os.path import expandvars as xpdVars … … 19 20 mkPath = lambda file: jnPath(os.environ['NDGSEC_WSSECLNT_UNITTEST_DIR'], file) 20 21 21 from elementtreeproxy import ElementTreeProxy22 from ndg.security.common.zsi_utils.elementtreeproxy import ElementTreeProxy 22 23 24 import logging 25 logging.basicConfig(level=logging.DEBUG) 26 log = logging.getLogger(__name__) 23 27 24 28 class EchoClientTestCase(unittest.TestCase): … … 48 52 49 53 # Signature handler object is passed to binding 54 # TODO: swap 'unsupressedPrefixes' to 'inclusive_namespaces' in 55 # wssecurity.WSSecurityConfig 50 56 sigHandler = SignatureHandler( 51 57 signingPriKeyFilePath=signingPriKeyFilePath, … … 53 59 signingCertFilePath=signingCertFilePath, 54 60 caCertFilePathList=caCertFilePathList, 55 refC14nKw={' unsuppressedPrefixes':[]},56 signedInfoC14nKw={' unsuppressedPrefixes':[]})61 refC14nKw={'inclusive_namespaces':[]}, 62 signedInfoC14nKw={'inclusive_namespaces':[]}) 57 63 58 64 locator = EchoServiceLocator() … … 67 73 '''test1Echo: test signed message and signed response from server''' 68 74 69 try: 75 try: 70 76 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") 72 80 except: 73 81 self.fail(traceback.print_exc()) -
TI12-security/trunk/python/Tests/etreewss/client/fred_eg.py
r4035 r4038 19 19 wsuNS='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' 20 20 env.set('xmlns:wsu', wsuNS) 21 body.set('wsu:Id', '#body') 21 env.set('URI', "http://blah") 22 #body.set('wsu:Id', '#body') 23 body.set('{%s}Id' % wsuNS, '#body') 22 24 ns = {'wsu': wsuNS} 23 25 print "wsu:Id elements = %s" % env.findall('.//*[@wsu:Id]', namespaces=ns) … … 38 40 print "wsu:Id elements = %s" % env2.findall('.//*[@wsu:Id]', namespaces=ns) 39 41 42 print "Calling C14N for echo message ..." 43 import pdb;pdb.set_trace() 44 45 etree = ElementC14N.parse('/home/pjkersha/Desktop/soap-etree.xml') 46 f = StringIO() 47 elem = etree.getroot() 48 elem._scope = etree._scope 49 ElementC14N.write(ElementC14N.build_scoped_tree(elem), f) 50 print f.getvalue() 40 51 41 52 53 -
TI12-security/trunk/python/Tests/etreewss/server/echoServer.py
r4024 r4038 7 7 8 8 # Import the ZSI stuff you'd need no matter what 9 from ZSI.ServiceContainer import ServiceContainer 9 from ZSI.ServiceContainer import ServiceContainer, SOAPRequestHandler, \ 10 SOAPContext, _contexts, SimpleWSResource, \ 11 ServiceInterface 10 12 11 13 # This is a new method imported to show it's value … … 15 17 EchoService as _EchoService 16 18 17 from ndg.security.common import wsSecurity 19 from ndg.security.common.wssecurity.etree import SignatureHandler 20 from ndg.security.common.zsi_utils.elementtreeproxy import ElementTreeProxy 18 21 19 22 from os.path import expandvars as xpdVars 20 23 from os.path import join as jnPath 21 24 mkPath = lambda file: jnPath(os.environ['NDGSEC_WSSESRV_UNITTEST_DIR'], file) 25 26 27 import thread 28 from ZSI.address import Address 29 from ZSI.parse import ParsedSoap 30 from ZSI.writer import SoapWriter 31 from ZSI import ParseException, FaultFromException, FaultFromZSIException, \ 32 Fault 33 34 import logging 35 logging.basicConfig(level=logging.DEBUG) 36 log = logging.getLogger(__name__) 37 38 class 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 93 def _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) 22 171 23 172 … … 43 192 '''\ 44 193 Overrides ServiceInterface class method to allow signature 45 verification''' 194 verification''' 46 195 self.signatureHandler.verify(ps) 47 196 … … 99 248 # Create the Inherited version of the server 100 249 echo = EchoService() 101 echo.signatureHandler = wsSecurity.SignatureHandler(cfg=wsseCfgFilePath)250 echo.signatureHandler = SignatureHandler(cfgFilePath=wsseCfgFilePath) 102 251 103 252 serviceContainer.setNode(echo, url=path) 253 serviceContainer.RequestHandlerClass = ElementTreeSOAPRequestHandler 104 254 105 255 try: -
TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/etree.py
r4035 r4038 1 """WS-Security test class includes digital signature handler1 """WS-Security digital signature handler for ElementTree XML package 2 2 3 3 NERC Data Grid Project 4 4 """ 5 5 __author__ = "P J Kershaw" 6 __date__ = "0 1/09/06"7 __copyright__ = "(C) 200 7STFC & NERC"6 __date__ = "02/07/08" 7 __copyright__ = "(C) 2008 STFC & NERC" 8 8 __license__ = \ 9 9 """This software may be distributed under the terms of the Q Public … … 18 18 from M2Crypto import X509, BIO, RSA 19 19 import base64 20 21 from elementtree import ElementTree, ElementC14N 22 from StringIO import StringIO 20 23 21 24 # Conditional import as this is required for the encryption … … 40 43 from ZSI.wstools.Namespaces import DSIG, ENCRYPTION, WSU, WSA200403, \ 41 44 SOAP, SCHEMA # last included for xsi 42 45 46 from ZSI.wstools.Namespaces import WSU as _WSU 43 47 from ZSI.wstools.Namespaces import OASIS as _OASIS 44 48 … … 55 59 from xml.xpath.Context import Context 56 60 from xml import xpath 57 58 # Include for re-parsing doc ready for canonicalization in sign method - see59 # associated note60 from xml.dom.ext.reader.PyExpat import Reader61 61 62 62 # Enable settings from a config file … … 77 77 BLOCK_TRIPLEDES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" 78 78 79 class _WSU(WSU):79 class WSU(_WSU): 80 80 '''Try different utility namespace for use with WebSphere''' 81 81 #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" 83 84 84 85 class OASIS(_OASIS): 85 86 # 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" 87 89 # wss4j 1.5.1 88 90 #WSSE11 = "http://docs.oasis-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-secext-1.1.xsd" … … 110 112 111 113 112 113 114 class WSSecurityError(Exception): 114 115 """For WS-Security generic exceptions not covered by other exception 115 116 classes in this module""" 116 117 117 class InvalidCertChain( Exception):118 class InvalidCertChain(WSSecurityError): 118 119 """Raised from SignatureHandler.verify if the certificate submitted to 119 120 verify a signature is not from a known CA""" 120 121 121 class VerifyError( Exception):122 class VerifyError(WSSecurityError): 122 123 """Raised from SignatureHandler.verify if an error occurs in the signature 123 124 verification""" 124 125 class TimestampError(Exception): 125 126 class NoSignatureFound(WSSecurityError): 127 """Incoming message to be verified was not signed""" 128 129 class TimestampError(WSSecurityError): 126 130 """Raised from SignatureHandler._verifyTimestamp if there is a problem with 127 131 the created or expiry times in an input message Timestamp""" 128 132 129 class InvalidSignature( Exception):133 class InvalidSignature(WSSecurityError): 130 134 """Raised from verify method for an invalid signature""" 131 135 132 class SignatureError( Exception):136 class SignatureError(WSSecurityError): 133 137 """Flag if an error occurs during signature generation""" 134 138 … … 160 164 } 161 165 166 binSecTokEncType = \ 167 "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" 162 168 163 169 #_________________________________________________________________________ … … 234 240 235 241 @param refC14nKw: dictionary of keywords to reference 236 Canonicalization. Use ' unsuppressedPrefixes' keyword to set237 unsuppressedPrefixes.242 Canonicalization. Use 'inclusive_namespaces' keyword to set 243 inclusive_namespaces. 238 244 @type refC14nKw: dict 239 245 … … 268 274 # TODO: get rid of refC14nKw and signedInfoC14nKw options 269 275 if len(self.cfg.get('refC14nInclNS', [])): 270 self.__setRefC14nKw({' unsuppressedPrefixes':276 self.__setRefC14nKw({'inclusive_namespaces': 271 277 self.cfg['refC14nInclNS']}) 272 278 else: … … 275 281 276 282 if len(self.cfg.get('signedInfoC14nNS', [])): 277 self.__setSignedInfoC14nKw({' unsuppressedPrefixes':283 self.__setSignedInfoC14nKw({'inclusive_namespaces': 278 284 self.cfg['signedInfoC14nNS']}) 279 285 else: … … 358 364 "Expecting dictionary type for reference c14n keywords" 359 365 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): 363 369 raise AttributeError, \ 364 370 'Expecting list or tuple of prefix names for "%s" keyword' % \ 365 ' unsuppressedPrefixes'371 'inclusive_namespaces' 366 372 367 373 … … 391 397 def __refC14nIsExcl(self): 392 398 return isinstance(self.__refC14nKw, dict) and \ 393 isinstance(self.__refC14nKw.get(' unsuppressedPrefixes'), list)399 isinstance(self.__refC14nKw.get('inclusive_namespaces'), list) 394 400 395 401 refC14nIsExcl = property(fget=__refC14nIsExcl, … … 400 406 def __signedInfoC14nIsExcl(self): 401 407 return isinstance(self.__signedInfoC14nKw, dict) and \ 402 isinstance(self.__signedInfoC14nKw.get(' unsuppressedPrefixes'), list)408 isinstance(self.__signedInfoC14nKw.get('inclusive_namespaces'), list) 403 409 404 410 signedInfoC14nIsExcl = property(fget=__signedInfoC14nIsExcl, … … 708 714 return 709 715 710 sigConfirmElem = wsseElem.createAppendElement(OASIS.WSSE11, 711 'SignatureConfirmation') 716 sigConfirmElem = ElementTree.Element("{%s}%s" % (OASIS.WSSE11, 717 'SignatureConfirmation')) 718 wsseElem.append(sigConfirmElem) 712 719 713 720 # 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") 715 722 716 723 # 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? 719 727 b64EncSignatureValue = ''.join(self.b64EncSignatureValue.split('\n')) 720 sigConfirmElem. _etree.set('Value', b64EncSignatureValue)728 sigConfirmElem.set('Value', b64EncSignatureValue) 721 729 722 730 … … 736 744 ''' 737 745 # 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 740 749 # 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") 742 751 743 752 # Value type can be any be any one of those supported via 744 753 # binSecTokValType 745 createdElem = timestampElem.createAppendElement(_WSU.UTILITY,'Created') 754 createdElem = ElementTree.Element("{%s}%s" % (WSU.UTILITY,'Created')) 755 timestampElem.append(createdElem) 756 746 757 dtCreatedTime = datetime.utcnow() 747 createdElem. createAppendTextNode(dtCreatedTime.isoformat('T')+'Z')758 createdElem.text = dtCreatedTime.isoformat('T') + 'Z' 748 759 749 760 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' 752 765 753 766 … … 817 830 818 831 # Namespaces for XPath searches 819 processorN ss = \832 processorNSs = \ 820 833 { 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 825 838 } 826 839 827 840 # Add X.509 cert as binary security token 841 # TODO: sub encodestring with b64encode? 828 842 if self.__reqBinSecTokValType==self.binSecTokValType['X509PKIPathv1']: 829 843 binSecTokVal = base64.encodestring(self.__signingCertChain.asDER()) … … 832 846 binSecTokVal = base64.encodestring(self.__signingCert.asDER()) 833 847 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) 838 859 839 860 try: 840 refC14nPfxSet = len(self.__refC14nKw[' unsuppressedPrefixes']) > 0861 refC14nPfxSet = len(self.__refC14nKw['inclusive_namespaces']) > 0 841 862 except KeyError: 842 863 refC14nPfxSet = False … … 844 865 try: 845 866 signedInfoC14nPfxSet = \ 846 len(self.__signedInfoC14nKw[' unsuppressedPrefixes']) > 0867 len(self.__signedInfoC14nKw['inclusive_namespaces']) > 0 847 868 except KeyError: 848 869 signedInfoC14nPfxSet = False 849 870 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 853 875 # Check <wsse:security> isn't already present in header 854 wsse Nodes = soapWriter.dom.evaluate('.//wsse:security',855 processorNss=processorNss)856 if len(wsse Nodes) > 1:876 wsseElems = self._soapEnvElem.findall('.//wsse:security', 877 namespaces=processorNSs) 878 if len(wsseElems) > 1: 857 879 raise SignatureError('wsse:Security element is already present') 858 880 859 881 # 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) 863 886 864 887 # Recipient MUST parse and check this signature 865 wsseElem. _etree.set('SOAP-ENV:mustUnderstand', "1")888 wsseElem.set('SOAP-ENV:mustUnderstand', "1") 866 889 867 890 # Binary Security Token element will contain the X.509 cert 868 891 # 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) 871 895 872 896 # Value type can be any be any one of those supported via 873 897 # 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) 879 900 880 901 # 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 884 905 885 906 … … 893 914 894 915 # 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) 897 918 898 919 # Signature - Signed Info 899 signedInfoElem = signatureElem.createAppendElement(DSIG.BASE,900 'SignedInfo')920 signedInfoElem = ElementTree.Element("{%s}%s"%(DSIG.BASE,'SignedInfo')) 921 signatureElem.append(signedInfoElem) 901 922 902 923 # 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) 905 927 906 928 # Set based on 'signedInfoIsExcl' property … … 908 930 signedInfoC14nAlg = c14nAlgOpt[int(self.signedInfoC14nIsExcl)] 909 931 910 c14nMethodElem. _etree.set('Algorithm', signedInfoC14nAlg)932 c14nMethodElem.set('Algorithm', signedInfoC14nAlg) 911 933 912 934 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 918 943 919 944 # 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) 923 949 924 950 # 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) 927 954 928 955 # 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) 932 962 933 963 # 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") 937 968 938 969 # 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 961 976 refC14nAlg = c14nAlgOpt[self.refC14nIsExcl] 962 977 978 # Pick up all the wsu:Id tagged elements set in the above 979 refElems = self._soapEnvElem.findall('.//*[@wsu:Id]', 980 namespaces=processorNSs) 981 963 982 # 1) Reference Generation 964 983 # 965 984 # Find references 966 for ref Node in refNodes:985 for refElem in refElems: 967 986 968 987 # 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')) 971 989 972 990 # 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() 980 999 981 1000 # Calculate digest for reference and base 64 encode 982 1001 # 983 1002 # 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 987 1008 # 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) 991 1012 992 1013 # 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) 997 1019 998 1020 # Set Canonicalization algorithm type 999 transformElem. _etree.set('Algorithm', refC14nAlg)1021 transformElem.set('Algorithm', refC14nAlg) 1000 1022 if refC14nPfxSet: 1001 1023 # Exclusive C14N requires inclusive namespace elements … … 1003 1025 refC14nAlg, 1004 1026 'InclusiveNamespaces') 1005 inclNamespacesElem._etree.set('PrefixList',1006 ' '.join(self.__refC14nKw['unsuppressedPrefixes']))1027 refPfxList = ' '.join(self.__refC14nKw['inclusive_namespaces']) 1028 inclNamespacesElem.set('PrefixList', refPfxList) 1007 1029 1008 1030 # 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) 1012 1036 1013 1037 # 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 1018 1042 1019 1043 # 2) Signature Generation 1020 1044 # 1021 1045 # 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 1043 1051 # Calculate digest of SignedInfo 1044 1052 signedInfoDigestValue = sha(c14nSignedInfo).digest() … … 1046 1054 # Sign using the private key and base 64 encode the result 1047 1055 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) 1049 1061 1050 1062 # Add to <SignatureValue> 1051 signatureValueElem.createAppendTextNode(b64EncSignatureValue) 1052 1053 log.info("Signature generation complete") 1063 signatureValueElem.text = b64EncSignatureValue 1064 log.debug("Signature generation complete") 1054 1065 1055 1066 … … 1061 1072 sender""" 1062 1073 1063 processorN ss = \1074 processorNSs = \ 1064 1075 { 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 1069 1080 } 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') 1078 1090 1079 1091 try: 1080 signature Nodes = signatureNodes[0]1092 signatureElems = signatureElems[0] 1081 1093 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 1085 1098 1086 1099 # Two stage process: reference validation followed by signature … … 1092 1105 # Use this later as a back up in case no Canonicalization was set in 1093 1106 # 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: 1103 1115 # Get the URI for the reference 1104 refURI = ref Node.getAttributeNode('URI').value1116 refURI = refElem.get('URI') 1105 1117 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") 1116 1126 1117 1127 # 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'] = [] 1138 1144 1139 1145 # Canonicalize the reference data and calculate the digest 1140 1146 if refURI[0] != "#": 1141 raise VerifyError ,\1142 "Expecting # identifier for Reference URI \"%s\"" % refURI1147 raise VerifyError('Expecting # identifier for Reference URI' \ 1148 ' "%s"' % refURI) 1143 1149 1144 1150 # 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() 1161 1172 1162 1173 # 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 1169 1188 # 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 1174 1194 # Get algorithm used for canonicalization of the SignedInfo 1175 1195 # element. Nb. This is NOT necessarily the same as that used to 1176 1196 # 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'] = [] 1197 1219 1198 1220 # 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) 1206 1223 signedInfoDigestValue = sha(c14nSignedInfo).digest() 1207 1224 1208 1225 # Get the signature value in order to check against the digest just 1209 1226 # 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) 1213 1229 1214 1230 # 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 1220 1232 signatureValue = base64.decodestring(b64EncSignatureValue) 1221 1233 … … 1228 1240 self.b64EncSignatureValue = None 1229 1241 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) 1274 1276 1275 1277 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") 1278 1280 1279 1281 # Extract RSA public key from the cert … … 1284 1286 verify = rsaPubKey.verify(signedInfoDigestValue, signatureValue) 1285 1287 except RSA.RSAError, e: 1286 raise VerifyError , "Error in Signature: " + str(e)1288 raise VerifyError("Error in Signature: " + str(e)) 1287 1289 1288 1290 if not verify: 1289 raise InvalidSignature , "Invalid signature"1291 raise InvalidSignature("Invalid signature") 1290 1292 1291 1293 # Verify chain of trust … … 1295 1297 self._verifyTimeStamp(parsedSOAP, ctxt) 1296 1298 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 7 7 from elementtree import ElementC14N, ElementTree 8 8 from StringIO import StringIO 9 10 from xml.dom import Node # Enable mimic of xml.dom behaviour 9 11 10 12 … … 21 23 _soap_enc_nsuri = SOAP.ENC 22 24 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 30 39 def __str__(self): 31 40 return self.toString() 32 41 33 42 def toString(self): 34 return ElementTree.tostring(self._etree)35 43 return self.canonicalize() 44 36 45 ############################################# 37 46 #Methods used in TypeCodes … … 53 62 # Search for matching prefix 54 63 matchingPrefix = None 55 for elem in self._e tree.getiterator():64 for elem in self._elem.getiterator(): 56 65 for k, v in elem.items(): 57 66 if k.startswith("xmlns:") and v == namespaceURI: … … 65 74 matchingPrefix = prefix 66 75 67 self._etree.set("xmlns:%s" % matchingPrefix, namespaceURI)76 elem.set("xmlns:%s" % matchingPrefix, namespaceURI) 68 77 else: 69 78 assert prefix, "Prefix must be set - no namespaceURI was provided" 70 print 'HELLO' 79 71 80 # Search for matching NS 72 81 for elem in self._etree.getiterator(): … … 77 86 78 87 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) 87 95 88 96 return eproxy … … 92 100 represented via this interface. Only 1 possible text node/element 93 101 ''' 94 self._e tree.text = pyobj102 self._elem.text = pyobj 95 103 96 104 def createDocument(self, namespaceURI=SOAP.ENV, localName='Envelope'): … … 98 106 prefix = self._soap_env_prefix 99 107 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) 102 111 103 112 def getElement(self, namespaceURI, localName): 104 for e in self._e tree.getchildren():113 for e in self._elem.getiterator(): 105 114 l = e.tag.strip('{').split('}') 106 115 if not namespaceURI: 107 116 if len(l) == 1 and l[0] == localName: 108 eproxy = ElementTreeProxy(None) 109 eproxy._etree = e 117 eproxy = ElementTreeProxy(elem=e, etree=self._etree) 110 118 return eproxy 111 119 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) 114 121 return eproxy 115 122 … … 119 126 def getPrefix(self, namespaceURI): 120 127 '''TODO: this is not possible w/elementTree since namespace prefix 121 mappings aren't done until serialization. completely abstrac ed 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" 124 131 125 132 def setAttributeNS(self, namespaceURI, localName, value): … … 132 139 ''' 133 140 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)) 134 145 135 146 def setAttributeType(self, namespaceURI, localName): … … 147 158 ''' 148 159 #self._etree.attrib["xmlns:%s" %prefix] = namespaceURI 149 self._e tree.set("xmlns:%s" % prefix, namespaceURI)160 self._elem.set("xmlns:%s" % prefix, namespaceURI) 150 161 151 162 def canonicalize(self, **kw): … … 173 184 # c14n = f.getvalue() 174 185 # 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 192 213 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 194 224 c14n = f.getvalue() 225 195 226 return c14n 227 196 228 197 229 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 296 from copy import deepcopy 297 298 def _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 15 15 ''' NDG equivalent to Shibboleth WAYF ''' 16 16 log.debug("WayfController.index ...") 17 17 18 # Check for return to arg in query. This is necessary only if the 18 19 # 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 9 9 [setUp] 10 10 #uri = http://localhost:7100/Echo 11 uri = http://localhost:7 200/Echo11 uri = http://localhost:7000/Echo 12 12 signingPriKeyFilePath = $NDGSEC_WSSECLNT_UNITTEST_DIR/clnt.key 13 13 signingPriKeyPwd = -
TI12-security/trunk/python/ndg.security.test/ndg/security/test/wsSecurity/server/echoServer.cfg
r3755 r4038 9 9 [setUp] 10 10 hostname = localhost 11 #port = 700012 port = 710011 port = 7000 12 #port = 7100 13 13 path = /Echo 14 14 wsseCfgFilePath = $NDGSEC_WSSESRV_UNITTEST_DIR/wssecurity.cfg
Note: See TracChangeset
for help on using the changeset viewer.