使用证书通过https跳过

And*_*sov 30 python ssl https suds

我在Apache下使用ssl进行soap服务,suds使用gres而不使用ssl.
我有客户端证书(my.crt和user.p12文件).
我需要如何配置suds客户端以使其与https服务一起使用?

没有证书,我明白了

urllib2.URLError: <urlopen error [Errno 1] _ssl.c:499: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure>

nit*_*wit 38

听起来您想要使用客户端证书进行身份验证,而不是像某些注释中所述的服务器证书.我有同样的问题,并能够为SUDS编写自定义传输.这是适用于我的代码.

您需要PEM格式的证书才能使用; OpenSSL可以轻松执行此转换,但我不记得确切的语法.

import urllib2, httplib, socket
from suds.client import Client
from suds.transport.http import HttpTransport, Reply, TransportError

class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
    def __init__(self, key, cert):
        urllib2.HTTPSHandler.__init__(self)
        self.key = key
        self.cert = cert

    def https_open(self, req):
        #Rather than pass in a reference to a connection class, we pass in
        # a reference to a function which, for all intents and purposes,
        # will behave as a constructor
        return self.do_open(self.getConnection, req)

    def getConnection(self, host, timeout=300):
        return httplib.HTTPSConnection(host,
                                       key_file=self.key,
                                       cert_file=self.cert)

class HTTPSClientCertTransport(HttpTransport):
    def __init__(self, key, cert, *args, **kwargs):
        HttpTransport.__init__(self, *args, **kwargs)
        self.key = key
        self.cert = cert

    def u2open(self, u2request):
        """
        Open a connection.
        @param u2request: A urllib2 request.
        @type u2request: urllib2.Requet.
        @return: The opened file-like urllib2 object.
        @rtype: fp
        """
        tm = self.options.timeout
        url = urllib2.build_opener(HTTPSClientAuthHandler(self.key, self.cert))
        if self.u2ver() < 2.6:
            socket.setdefaulttimeout(tm)
            return url.open(u2request)
        else:
            return url.open(u2request, timeout=tm)

# These lines enable debug logging; remove them once everything works.
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.DEBUG)
logging.getLogger('suds.transport').setLevel(logging.DEBUG)

c = Client('https://YOUR_URL_HERE',
    transport = HTTPSClientCertTransport('PRIVATE_KEY.pem',
                                         'CERTIFICATE_CHAIN.pem'))
print c
Run Code Online (Sandbox Code Playgroud)

  • "听起来你想要使用客户端证书进行身份验证,而不是像某些评论中所述的服务器证书." 此代码不对服务器进行身份验证:实质上,您将客户端证书发送给某些东西,但您尚未验证该内容是什么.这些都不会对服务器进行身份验证,无论您是否使用客户端证书,都应首先执行此操作. (3认同)

k4m*_*4ml 11

另一种解决方法是使用请求库作为传输,它更好地支持ssl.这就是我现在使用suds通过https访问SOAP服务的方法: -

import requests
from suds.transport.http import HttpAuthenticated
from suds.transport import Reply, TransportError

class RequestsTransport(HttpAuthenticated):
    def __init__(self, **kwargs):
        self.cert = kwargs.pop('cert', None)
        # super won't work because not using new style class
        HttpAuthenticated.__init__(self, **kwargs)

    def send(self, request):
        self.addcredentials(request)
        resp = requests.post(request.url, data=request.message,
                             headers=request.headers, cert=self.cert)
        result = Reply(resp.status_code, resp.headers, resp.content)
        return result
Run Code Online (Sandbox Code Playgroud)

然后你可以将suds客户端实例化为: -

headers = {"Content-TYpe" : "text/xml;charset=UTF-8",
           "SOAPAction" : ""}
t = RequestsTransport(cert='/path/to/cert', **credentials)
client = Client(wsdl_uri, location=send_url, headers=headers,
                transport=t))
Run Code Online (Sandbox Code Playgroud)

更新

我们现在正在使用Zeep,它requests在下面使用.

  • 如果您的soap端点需要http基本身份验证,那么`credentials = {'username':'yourname','password':'yourpass'}`. (2认同)
  • @GiovanniP,是的,您还需要覆盖open()方法.我编辑了答案,希望它被接受. (2认同)

And*_*ras 6

根据@ k4ml的答案,我只添加了open()允许使用证书获取WSDL的内容.

此方法应该suds.transport.TransportError: HTTP Error 403: Forbidden在尝试获取HTTPS服务后面提供的WSDL(在客户端创建时)时进行修复.

import requests
from suds.transport.http import HttpAuthenticated
from suds.transport import Reply, TransportError

class RequestsTransport(HttpAuthenticated):
    def __init__(self, **kwargs):
        self.cert = kwargs.pop('cert', None)
        # super won't work because not using new style class
        HttpAuthenticated.__init__(self, **kwargs)

    def open(self, request):
        """
        Fetches the WSDL using cert.
        """
        self.addcredentials(request)
        resp = requests.get(request.url, data=request.message,
                             headers=request.headers, cert=self.cert)
        result = io.StringIO(resp.content.decode('utf-8'))
        return result

    def send(self, request):
        """
        Posts to service using cert.
        """
        self.addcredentials(request)
        resp = requests.post(request.url, data=request.message,
                             headers=request.headers, cert=self.cert)
        result = Reply(resp.status_code, resp.headers, resp.content)
        return result
Run Code Online (Sandbox Code Playgroud)

旁注,我也建议编辑k4ml的答案,但它可能需要很长时间才能获得批准.