我正在尝试调用在以下.PEM验证的zeep客户端会话中启动的服务:
from requests import Session
from zeep import Client
from zeep.settings import Settings
from zeep.transports import Transport
from cryptography.hazmat.primitives.serialization import pkcs12
from cryptography.hazmat.primitives import serialization
session = Session()
session.verify = True
private_key, certificate, additional_certificates = pkcs12.load_key_and_certificates(
open(pfx_cert_path, "rb").read(), cert_psw_b)
key_tmpfile = tempfile.NamedTemporaryFile(dir="C:/Users/USERA/Anaconda3/envs/env/"
key_tmpfile.write(
private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
)
key_tmpfile.flush()
cert_tmpfile=tempfile.NamedTemporaryFile(dir="C:/Users/USERA/Anaconda3/envs/env/")
cert_tmpfile.write(
certificate.public_bytes(serialization.Encoding.PEM),
)
cert_tmpfile.flush()
session.cert = cert_tmpfile.name, key_tmpfile.name
settings = Settings(raw_response=True)
soap_client = Client(wsdl_url, transport=Transport(session=session), settings=settings)
字符串
我发送的内容包含一个SOAP-Body和一个SOAP-Header,它们都是动态值。我的做法类似于:soap_client.service.UploadMethod({"body_field":"body_value","_soapheaders":{"head_field":"head_value"}})
这会产生以下错误队列,当urllib 3以读取模式访问临时文件时,这些错误以Permission Denied结束。
File "C:\Users\USERA\Anaconda3\envs\env\lib\site-packages\urllib3\connection.py", line 419, in connect
self.sock = ssl_wrap_socket(
File "C:\Users\USERA\Anaconda3\envs\env\lib\site-packages\urllib3\util\ssl_.py", line 413, in ssl_wrap_socket
if keyfile and key_password is None and _is_key_file_encrypted(keyfile):
File "C:\Users\USERA\Anaconda3\envs\env\lib\site-packages\urllib3\util\ssl_.py", line 472, in _is_key_file_encrypted
with open(key_file, "r") as f:
PermissionError: [Errno 13] Permission denied:
型
我尝试过不同的位置。我也尝试过使用Suds客户端或直接依赖请求来进行soap调用,但我无法加载.pem证书和密钥。目前我设法在C#中简单地做到这一点,如下所示:
CLIENT client = new CLIENT(); // Project -> Add Service Reference -> Advanced -> Add Web Reference -> https://service_domain/service.asmx -> Rename "CLIENT"
string cert_path = "C:/PATH/Certificates/PKCS12_Credential.pfx";
string cert_psw_path = "C:/PATH/Certificates/psw_pfx.txt";
X509Certificate2 certificate = new X509Certificate2(cert_path, File.OpenText(cert_psw_path).ReadLine());
client.ClientCertificates.Add(certificate);
client.Login("", ""); // Which loads the soap headers
string xml_body = "C:/PATH/Body.txt";
client.UploadMethod(File.ReadAllText(xml_body));
型
有没有人知道如何解决这个问题?也许是通过改变urllib版本,或者使用一种替代方法,直接将证书作为字节串而不是路径文件传递?
先谢了。
1条答案
按热度按时间a5g8bdjr1#
在Windows上尝试访问
tempfile.NamedTemporaryFile
在Python中创建的临时文件时,似乎遇到了权限问题。这是用户在Windows上使用此函数时遇到的常见问题,因为操作系统不允许多个进程打开同一文件。urllib 3库以读取模式打开文件,这将导致PermissionError
,因为临时文件在Python代码中仍然打开。要解决此问题,您可以避免创建临时文件并直接从内存加载证书和密钥。这可以通过使用
load_cert_chain()
方法来完成,该方法接受证书和密钥的二进制数据,而不是文件路径。您可以使用
private_bytes
和public_bytes
方法将私钥和证书转换为字符串,将其解码为UTF-8,然后使用ssl.SSLContext()
将字符串提供给ssl上下文。下面,请找到一个不使用tempfile的示例实现,使用Zeep的低级内置支持来提供自定义传输:字符串
请注意,
ssl_context
参数在创建Transport对象时使用。这将允许您传递包含证书和密钥的SSL上下文,以与Web服务通信。另外,请记住将
wsdl_url
和MyMethod()
替换为您自己的Web服务详细信息。请注意,session
也需要正确初始化和配置。这种方法应该可以避免您面临的
PermissionError
问题,因为它绕过了创建临时文件的需要,并将证书和密钥直接加载到SSL上下文中。请记住,要确保这些字符串的安全,因为它们将包含非常敏感的密钥和证书数据。