python-3.x 在Soap客户端方法调用期间权限被拒绝13,

w6lpcovy  于 2024-01-10  发布在  Python
关注(0)|答案(1)|浏览(201)

我正在尝试调用在以下.PEM验证的zeep客户端会话中启动的服务:

  1. from requests import Session
  2. from zeep import Client
  3. from zeep.settings import Settings
  4. from zeep.transports import Transport
  5. from cryptography.hazmat.primitives.serialization import pkcs12
  6. from cryptography.hazmat.primitives import serialization
  7. session = Session()
  8. session.verify = True
  9. private_key, certificate, additional_certificates = pkcs12.load_key_and_certificates(
  10. open(pfx_cert_path, "rb").read(), cert_psw_b)
  11. key_tmpfile = tempfile.NamedTemporaryFile(dir="C:/Users/USERA/Anaconda3/envs/env/"
  12. key_tmpfile.write(
  13. private_key.private_bytes(
  14. encoding=serialization.Encoding.PEM,
  15. format=serialization.PrivateFormat.PKCS8,
  16. encryption_algorithm=serialization.NoEncryption(),
  17. )
  18. )
  19. key_tmpfile.flush()
  20. cert_tmpfile=tempfile.NamedTemporaryFile(dir="C:/Users/USERA/Anaconda3/envs/env/")
  21. cert_tmpfile.write(
  22. certificate.public_bytes(serialization.Encoding.PEM),
  23. )
  24. cert_tmpfile.flush()
  25. session.cert = cert_tmpfile.name, key_tmpfile.name
  26. settings = Settings(raw_response=True)
  27. 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结束。

  1. File "C:\Users\USERA\Anaconda3\envs\env\lib\site-packages\urllib3\connection.py", line 419, in connect
  2. self.sock = ssl_wrap_socket(
  3. File "C:\Users\USERA\Anaconda3\envs\env\lib\site-packages\urllib3\util\ssl_.py", line 413, in ssl_wrap_socket
  4. if keyfile and key_password is None and _is_key_file_encrypted(keyfile):
  5. File "C:\Users\USERA\Anaconda3\envs\env\lib\site-packages\urllib3\util\ssl_.py", line 472, in _is_key_file_encrypted
  6. with open(key_file, "r") as f:
  7. PermissionError: [Errno 13] Permission denied:


我尝试过不同的位置。我也尝试过使用Suds客户端或直接依赖请求来进行soap调用,但我无法加载.pem证书和密钥。目前我设法在C#中简单地做到这一点,如下所示:

  1. CLIENT client = new CLIENT(); // Project -> Add Service Reference -> Advanced -> Add Web Reference -> https://service_domain/service.asmx -> Rename "CLIENT"
  2. string cert_path = "C:/PATH/Certificates/PKCS12_Credential.pfx";
  3. string cert_psw_path = "C:/PATH/Certificates/psw_pfx.txt";
  4. X509Certificate2 certificate = new X509Certificate2(cert_path, File.OpenText(cert_psw_path).ReadLine());
  5. client.ClientCertificates.Add(certificate);
  6. client.Login("", ""); // Which loads the soap headers
  7. string xml_body = "C:/PATH/Body.txt";
  8. client.UploadMethod(File.ReadAllText(xml_body));


有没有人知道如何解决这个问题?也许是通过改变urllib版本,或者使用一种替代方法,直接将证书作为字节串而不是路径文件传递?
先谢了。

a5g8bdjr

a5g8bdjr1#

在Windows上尝试访问tempfile.NamedTemporaryFile在Python中创建的临时文件时,似乎遇到了权限问题。这是用户在Windows上使用此函数时遇到的常见问题,因为操作系统不允许多个进程打开同一文件。urllib 3库以读取模式打开文件,这将导致PermissionError,因为临时文件在Python代码中仍然打开。
要解决此问题,您可以避免创建临时文件并直接从内存加载证书和密钥。这可以通过使用load_cert_chain()方法来完成,该方法接受证书和密钥的二进制数据,而不是文件路径。
您可以使用private_bytespublic_bytes方法将私钥和证书转换为字符串,将其解码为UTF-8,然后使用ssl.SSLContext()将字符串提供给ssl上下文。下面,请找到一个不使用tempfile的示例实现,使用Zeep的低级内置支持来提供自定义传输:

  1. import ssl
  2. from zeep import Client, Settings, Plugin
  3. from zeep.transports import Transport
  4. from cryptography.hazmat.primitives.serialization import pkcs12
  5. from cryptography.hazmat.primitives import serialization
  6. private_key, certificate, additional_certificates = pkcs12.load_key_and_certificates(
  7. open(pfx_cert_path, "rb").read(), cert_psw_b)
  8. context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
  9. context.load_cert_chain(
  10. certfile=certificate.public_bytes(serialization.Encoding.PEM).decode('utf-8'),
  11. keyfile=private_key.private_bytes(
  12. encoding=serialization.Encoding.PEM,
  13. format=serialization.PrivateFormat.PKCS8,
  14. encryption_algorithm=serialization.NoEncryption()
  15. ).decode('utf-8'))
  16. settings = Settings(strict=True, xml_huge_tree=True)
  17. client = Client(wsdl_url,
  18. plugins=[MyLoggingPlugin()],
  19. transport=Transport(session=session, timeout=10, operation_timeout=10, ssl_context=context),
  20. settings=settings)
  21. response = client.service.MyMethod()

字符串
请注意,ssl_context参数在创建Transport对象时使用。这将允许您传递包含证书和密钥的SSL上下文,以与Web服务通信。
另外,请记住将wsdl_urlMyMethod()替换为您自己的Web服务详细信息。请注意,session也需要正确初始化和配置。
这种方法应该可以避免您面临的PermissionError问题,因为它绕过了创建临时文件的需要,并将证书和密钥直接加载到SSL上下文中。请记住,要确保这些字符串的安全,因为它们将包含非常敏感的密钥和证书数据。

展开查看全部

相关问题