如何在Python中签名SOAP消息并生成WSS安全头?
在Python中为SOAP消息添加WS-Security签名及指定安全头
问题描述
需要为指定SOAP消息生成签名,最终输出必须包含要求的WS-Security安全头。曾尝试使用xmlsectool-3.0.0,但无法添加带有正确命名空间的所需头。
原始SOAP消息
<SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"> <ns1:RequestSecurityTokenCollection> <ns1:RequestSecurityToken> <wsp:AppliesTo> <wsa:EndpointReference> <wsa:Address>https://abcd</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <wst:Issuer> <wsa:Address>https://xyz</wsa:Address> </wst:Issuer> <wst:TokenType>urn:ietf:params:oauth:token-type:jwt</wst:TokenType> <wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Validate</wst:RequestType> <wst:Base> <stsuuser:STSUniversalUser xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser"> <stsuuser:Principal> <stsuuser:Attribute name="name"> <stsuuser:Value>john</stsuuser:Value> </stsuuser:Attribute> </stsuuser:Principal> <stsuuser:AttributeList/> </stsuuser:STSUniversalUser> </wst:Base> </ns1:RequestSecurityToken> </ns1:RequestSecurityTokenCollection> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
要求的安全头
<SOAP-ENV:Header> <wss:Security xmlns:wss="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="NEWID"> <wsu:Created/> </wsu:Timestamp> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id=""> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>96njoA0fzM8X6G5PWjOp+R4/Gi4=</ds:DigestValue> </ds:Reference> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>EXY1Zah4kwz4Dlhc0G3oHIy7HJU=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>Jdkt8TaBmtJGDnsSIdoOibfGAXbqXkKxS4TkQwEfUTWLHyMPe2RqQ1E0ziK1bLU5 CKAcAQ+eRgymP68Zlu3ahW56dTYSBA1DxFFFfD8CtCPikEuQSwMPBWZK5yzlMRm4 ZHv+/XOXYtZRBTT3C+34AAYNn77bE+AAjpcp4VP+xLqv4efTYz/fHVzVkxIh1WpA tOw0e0WcNrBls1tMe191pAXOJgUXgNChTnGnpr4IVSHinv+HtS54oe0bZwlL3yBp Gqsq/sIM9pbaTykGW4i6jV9G3vkDiFN2xd/3A45+TQCNu8YXQD9enc96wzVY8LGT aeYdEXMT9bgNqe1ayqM0NA==</ds:SignatureValue> </ds:Signature> </wss:Security> </SOAP-ENV:Header>
解决方案
可以使用Python的zeep库配合xmlsec实现WS-Security签名,具体步骤如下:
1. 安装依赖库
pip install zeep xmlsec
2. 编写签名代码
from zeep.wsse.signature import Signature from datetime import datetime from lxml import etree # 加载原始SOAP消息 soap_content = """ <SOAP-ENV:Envelope xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"> <SOAP-ENV:Body> <ns1:RequestSecurityTokenCollection> <ns1:RequestSecurityToken> <wsp:AppliesTo> <wsa:EndpointReference> <wsa:Address>https://abcd</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <wst:Issuer> <wsa:Address>https://xyz</wsa:Address> </wst:Issuer> <wst:TokenType>urn:ietf:params:oauth:token-type:jwt</wst:TokenType> <wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Validate</wst:RequestType> <wst:Base> <stsuuser:STSUniversalUser xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser"> <stsuuser:Principal> <stsuuser:Attribute name="name"> <stsuuser:Value>john</stsuuser:Value> </stsuuser:Attribute> </stsuuser:Principal> <stsuuser:AttributeList/> </stsuuser:STSUniversalUser> </wst:Base> </ns1:RequestSecurityToken> </ns1:RequestSecurityTokenCollection> </SOAP-ENV:Body> </SOAP-ENV:Envelope> """ # 转换为lxml元素对象 root = etree.fromstring(soap_content.encode('utf-8')) # 配置签名参数,替换为你的私钥和证书路径 signature = Signature( private_key_file='你的私钥路径.pem', certificate_file='你的证书路径.pem', signature_method='http://www.w3.org/2000/09/xmldsig#rsa-sha1', canonicalization_method='http://www.w3.org/2001/10/xml-exc-c14n#' ) # 创建符合要求的Timestamp头 timestamp = signature._create_timestamp() timestamp.set('wsu:Id', 'NEWID') created_node = timestamp.find('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Created') created_node.text = datetime.utcnow().isoformat() + 'Z' # 获取或创建SOAP Header节点 soap_header = root.find('{http://schemas.xmlsoap.org/soap/envelope/}Header') if soap_header is None: soap_header = etree.SubElement(root, '{http://schemas.xmlsoap.org/soap/envelope/}Header') # 创建Security头并添加Timestamp security_ns = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' security_node = etree.SubElement(soap_header, '{' + security_ns + '}Security') security_node.append(timestamp) # 对Body和Timestamp进行签名 soap_body = root.find('{http://schemas.xmlsoap.org/soap/envelope/}Body') signature.sign_envelope(root, [soap_body, timestamp]) # 输出签名后的完整SOAP消息 print(etree.tostring(root, pretty_print=True, encoding='utf-8').decode('utf-8'))
关键说明
- 代码中手动构建了符合要求的
Timestamp节点,设置了指定的wsu:Id并填充当前UTC时间 - 通过
zeep的Signature类自动生成符合规范的签名节点,包含指定的算法和引用规则 - 签名对象同时包含SOAP Body和Timestamp,与需求中的双引用结构匹配
- 需替换代码中的私钥和证书路径为实际文件路径,确保两者匹配
内容的提问来源于stack exchange,提问作者Redhat
相关产品推荐
相关产品推荐

