python ssl https suds

python - Suds sobre https con cert



ssl (5)

Basado en la respuesta de @k4ml, solo he agregado el open() que permite buscar el WSDL usando el certificado.

Este método debería corregir el suds.transport.TransportError: HTTP Error 403: Forbidden cuando se intenta obtener un WSDL (en la creación del Cliente) servido detrás de un servicio HTTPS.

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

Nota al margen, también hice una edición sugerida a la respuesta de k4ml, pero puede tomar años antes de que se apruebe.

Tengo el servicio de jabón en Apache con SSL, la espuma funciona mejor sin SSL.
Tengo certificado de cliente (archivos my.crt y user.p12).
¿Cómo debo configurar el cliente de suds para que funcione con el servicio en https?

sin certs veo

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


Extendiendo la solución @ k4ml, usando cert + key Esto resolverá excepciones como:

requests.exceptions.SSLError: [SSL] PEM lib (_ssl.c:2599)

Solución:

import requests from suds.client import Client 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) 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, verify=True ) result = Reply(resp.status_code, resp.headers, resp.content) return result t = RequestsTransport(cert=(''<your cert.pem path>'', ''your key.pem path'')) headers = {"Content-Type": "text/xml;charset=UTF-8", "SOAPAction": ""} client = Client(wsdl_url, headers=headers, transport=t)


La característica de seguridad SSL se habilita automáticamente en python 2.7.9+, lo que rompe las jabonaduras y otras bibliotecas de Python. Estoy compartiendo un parche que puede solucionarlo:

Ubica la biblioteca de suds y reemplaza la función de u2handlers en el archivo suds / trasnport / http.py con la siguiente línea:

import ssl def u2handlers(self): """ Get a collection of urllib handlers. @return: A list of handlers to be installed in the opener. @rtype: [Handler,...] """ handlers = [] unverified_context = ssl.create_default_context() unverified_context.check_hostname = False unverified_context.verify_mode = ssl.CERT_NONE unverified_handler = urllib2.HTTPSHandler(context=unverified_context) handlers.append(unverified_handler) handlers.append(urllib2.ProxyHandler(self.proxy)) #handlers.append(urllib2.ProxyHandler(self.proxy)) return handlers

Nota: No es una forma recomendada de hacerlo.


Otra solución consiste en utilizar las solicitudes de biblioteca como transporte, que tiene una mejor compatibilidad con ssl. Esto es lo que estoy usando ahora para acceder a los servicios SOAP a través de https usando espuma: -

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

Y luego puedes instanciar el cliente de suds como:

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))

Actualizar

Ahora estamos usando Zeep , que usa requests debajo.


Parece que desea autenticarse utilizando un certificado de cliente , no un certificado de servidor , como se indicó en algunos de los comentarios. Tuve el mismo problema y pude escribir un transporte personalizado para SUDS. Aquí está el código que funciona para mí.

Necesitará sus certificados en formato PEM para que esto funcione; OpenSSL puede realizar fácilmente esta conversión, aunque no recuerdo la sintaxis exacta.

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(''YOUR_KEY_AND_CERT.pem'', ''YOUR_KEY_AND_CERT.pem'')) print c