J'ai un service de savon sous Apache avec ssl, suds fonctionne greate sans ssl.
J'ai un certificat client (mes fichiers .crt et user.p12).
Comment dois-je configurer le client suds pour le faire fonctionner avec le service via https?
sans certificats je vois
urllib2.URLError: <erreur urlopen [Errno 1] _ssl.c: 499: erreur: 14094410: routines SSL: SSL3_READ_BYTES: échec de la négociation de l'alerte sslv3>
Il semble que vous souhaitiez vous authentifier à l'aide d'un certificat client, et non d'un certificat serveur comme cela a été indiqué dans certains commentaires. J'ai eu le même problème et j'ai pu écrire un transport personnalisé pour SUDS. Voici le code qui fonctionne pour moi.
Vous aurez besoin de vos certificats au format PEM pour que cela fonctionne; OpenSSL peut facilement effectuer cette conversion, bien que je ne me souvienne pas de la syntaxe exacte.
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
Une autre solution consiste à utiliser la bibliothèque de demandes comme moyen de transport qui prend mieux en charge SSL. Voici ce que j'utilise maintenant pour accéder aux services SOAP via https à l'aide de mousse: -
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
Et puis vous pouvez instancier le client de mousse comme: -
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))
Mise à jour
Nous utilisons maintenant Zeep , qui utilise requests
en dessous.
Sur la base de la réponse @ k4ml, je n'ai ajouté que la open()
qui permet de récupérer le WSDL à l'aide du certificat.
Cette méthode devrait corriger le suds.transport.TransportError: HTTP Error 403: Forbidden
lors de la tentative de récupération d'un WSDL (lors de la création du client) servi derrière un service 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
Note latérale, j'ai également suggéré de modifier la réponse de k4ml, mais cela peut prendre un certain temps avant d'être approuvé.
Étendre la solution @ k4ml, en utilisant la clé cert + Cela résoudra des exceptions comme:
requests.exceptions.SSLError: [SSL] PEM lib (_ssl.c:2599)
Solution:
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 fonction de sécurité SSL est activée automatiquement python 2.7.9+ qui rompt la mousse et les autres bibliothèques python. Je partage un correctif qui peut résoudre ce problème:
Localisez votre bibliothèque suds et remplacez la fonction u2handlers dans le fichier suds/trasnport/http.py par la ligne suivante:
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
Remarque: ce n'est pas une façon recommandée de le faire.