L’API Python HTTPS contre Azure Service Management échoue sous Windows

J’ai récemment étendu une API Python pour les API de stockage Windows Azure (PyAzure) afin d’inclure la prise en charge des API de gestion des services. Voir https://github.com/bmb/pyazuree .

J’utilise un HTTPSClientAuthHandler comme celui proposé en utilisant pyOpenSSL pour créer un ouvre-fichier personnalisé urllib . Sous Linux, avec différentes versions de Python 2.6 et 2.7, cela fonctionne bien. Cependant, Windows est une autre histoire. Toutes les demandes concernant l’adresse de l’hôte de gestion Azure échouent avec:

[Errno 10054] Une connexion existante a été fermée de force par l’hôte distant

Ce que je pense, est le socket errno 10054 “Connexion réinitialisée par des pairs”, en glisser.

Cela ne semble pas être un problème dans mon code API (à moins que la méthode d’authentification certifiée par le client que j’utilise soit fausse), mais quelque chose de moins important. Je peux reproduire le problème sans urllib2 ou httplib en configurant simplement un socket SSL et en envoyant la même requête HTTP sur le canal que si urllib2 le souhaitait, par exemple pour répertorier les emplacements de centre de données Azure valides:

>>> import socket, ssl, sys >>> sys.version '2.7.1 (r271:86832, Nov 27 2010, 17:19:03) [MSC v.1500 64 bit (AMD64)]' >>> s = ssl.wrap_socket(socket.socket(), certfile='c:\\users\\blair\\research\\clouds\\azuree\\BlairBethwaiteAzure1.pfx.pem') >>> s.connect(('management.core.windows.net',443)) >>> s.send("GET /SUBSCRIPTION_ID/locations HTTP/1.1\r\nAccept-Encoding: identity\r\nX-Ms-Version: 2011-10-01\r\nHost: management.core.windows.net\r\nConnection: close\r\nUser-Agent: Python-urllib/2.6\r\n\r\n") 202 >>> s.read() Traceback (most recent call last): c:\Users\blair\research\clouds\azuree\pyazuree\ in () ----> 1 s.read() C:\Python27\lib\ssl.pyc in read(self, len) 136 137 try: --> 138 return self._sslobj.read(len) 139 except SSLError, x: 140 if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: error: [Errno 10054] An existing connection was forcibly closed by the remote host 

Remplacez SUBSCRIPTION_ID ci-dessus par votre ID d’abonnement Azure. L’exception est levée ~ 45 secondes après l’appel de SSLSocket.read. Le cert est un fichier PEM correctement formaté comprenant à la fois la clé privée et le certificate, il a été converti à partir du fichier pfx (dans Ubuntu 10.04) en utilisant:

openssl pkcs12 -in pfxfile -out pemfile -nodes

Je ne pense pas que ce soit important ici, mais j’ai aussi essayé de décompresser le fichier PEM en unix2, mais en vain. J’obtiens le même comportement même si je ne fournis aucun certificate, mais le faire sous Linux entraîne une erreur API correcte du serveur:

‘HTTP / 1.1 403 Forbidden \ r \ nContent-Length: 0 \ r \ nServer: Microsoft-HTTPAPI / 2.0 \ r \ nDate: jeu. 01 déc. 2011 13:59:29 GMT \ r \ nConnexion: close \ r \ n \ r \ n ‘

Cela a été vérifié indépendamment par une autre personne utilisant Windows 7 (comme moi). Ce n’est pas un problème de pare-feu côté client – le même code fonctionne dans une machine virtuelle Linux NAT-ed exécutée sur le même hôte.

Je suis déconcerté. J’apprécierais vraiment toute aide que les gens ici pourraient fournir …

Mise à jour: cela semble être lié à l’implémentation SSL sous-jacente en Python. CPython 2.7.1 a le comportement d’erreur indiqué ci-dessus, mais j’ai depuis testé et réussi avec ActiveState Python (à la fois 2.7 et 2.6), par exemple:

 >>> import sys, socket, ssl >>> sys.version '2.7.1 (r271:86832, Feb 7 2011, 11:30:38) [MSC v.1500 32 bit (Intel)]' >>> s = ssl.wrap_socket(socket.socket(), certfile='\\\\VBOXSVR\\azuree\\BlairBethwaiteAzure1.pfx.pem') >>> s.connect(('management.core.windows.net',443)) >>> s.send('GET /SUBSCRIPTION_ID/locations HTTP/1.1\r\nAccept-Encoding: identity\r\nX-Ms-Version: 2011-10-01\r\nHost: management.core.windows.net\r\nUser-Agent: Python-urllib/2.6\r\n\r\n') 183 >>> s.read(4096) 'HTTP/1.1 200 OK\r\nContent-Length: 908\r\nContent-Type: application/xml; charset=utf-8\r\nServer: Microsoft-HTTPAPI/2.0\r\nx-ms-request-id: 08ca048cda6b445da6b3a8f3e4890197\r\nDate: Fri, 02 Dec 2011 03:02:14 GMT\r\n\r\nAnywhere USAnywhere USSouth Central USSouth Central USNorth Central USNorth Central USAnywhere EuropeAnywhere EuropeNorth EuropeNorth EuropeWest EuropeWest EuropeAnywhere AsiaAnywhere AsiaSoutheast AsiaSoutheast AsiaEast AsiaEast Asia' 

Et comme prévu, mon API fonctionne aussi:

 ActivePython 2.6.7.20 (ActiveState Software Inc.) based on Python 2.6.7 (r267:88850, Jun 27 2011, 13:20:48) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> from pyazuree import pyazuree >>> pa = pyazuree.PyAzure(subscription_id=SUBSCRIPTION_ID, management_cert_path='c:\\users\\blair\\research\\clouds\\azuree\\BlairBethwaiteAzure1.pfx.pem') >>> list(pa.wasm.list_locations()) ['Anywhere US', 'South Central US', 'North Central US', 'Anywhere Europe', 'North Europe', 'West Europe', 'Anywhere Asia', 'Southeast Asia', 'East Asia'] 

Les fichiers Lib \ ssl.py dans CPython2.7 et ActivePython2.7 sont identiques, donc je suppose que cela est dû à une différence dans les librairies C sous-jacentes, peut-être un bogue dans CPython. Des gourous dehors?

Je n’ai pas été en mesure de trouver une explication définitive pour cela, mais après un peu d’essais et d’erreurs, je suis confiant sur l’endroit où le problème se pose …

Réponse courte: c’est l’implémentation ssl dans le bundle http://www.python.org/ Windows. Utilisez plutôt ActiveState Python.

Réponse longue: Les dissortingbutions Windows CPython disponibles à partir de http://www.python.org/download/ regroupent une ancienne version d’OpenSSL (0.9.8l), comparée aux dissortingbutions ActiveState Python basées sur CPython mais (entre autres choses). ) fournir des mises à jour régulières aux inclusions tierces telles que OpenSSL (actuellement 0.9.8r).

J’ai téléchargé des binarys Windows d’OpenSSL et testé via l’interface openssl s_client, par exemple:

openssl s_client -connect management.core.windows.net:443 -cert /home/blair/nimrod-dev/BlairBethwaiteAzure1.pfx.pem

La version actuelle fonctionne comme prévu. Malheureusement, il semble difficile de mettre la main sur d’anciens binarys OpenSSL pour Windows, ce qui n’est peut-être pas surprenant étant donné qu’il s’agit d’une bibliothèque de sécurité … Mais de toute façon, j’ai construit 0.9.8l à partir de sources sous Ubuntu 10.04. le tuyau, probablement le serveur a silencieusement laissé tomber la connexion pour une raison quelconque:

 blair@venus-vm:~/Downloads/openssl-0.9.8l/apps$ ./openssl s_client -connect management.core.windows.net:443 -cert ./BlairAzure.pem CONNECTED(00000003) depth=2 /CN=Microsoft Internet Authority verify error:num=20:unable to get local issuer certificatee verify return:0 --- Certificate chain 0 s:/CN=management.core.windows.net i:/DC=com/DC=microsoft/DC=corp/DC=redmond/CN=Microsoft Secure Server Authority 1 s:/DC=com/DC=microsoft/DC=corp/DC=redmond/CN=Microsoft Secure Server Authority i:/CN=Microsoft Internet Authority 2 s:/CN=Microsoft Internet Authority i:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root --- Server certificatee -----BEGIN CERTIFICATE----- MIIGhDCCBWygAwIBAgIKFnL3ogAIAAIjlDANBgkqhkiG9w0BAQUFADCBizETMBEG CgmSJomT8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEUMBIG CgmSJomT8ixkARkWBGNvcnAxFzAVBgoJkiaJk/IsZAEZFgdyZWRtb25kMSowKAYD VQQDEyFNaWNyb3NvZnQgU2VjdXJlIFNlcnZlciBBdXRob3JpdHkwHhcNMTEwNjE2 MDg0MjI3WhcNMTMwNjE1MDg0MjI3WjAmMSQwIgYDVQQDExttYW5hZ2VtZW50LmNv cmUud2luZG93cy5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCS Z9PTUqQLh5keX/IRJ6JxaQkVBIy/iyoCIx2Y0zy5F5tll8CRydGzFDjXMLWEG425 EuuRDQrBgQnmVtlZ2t42QfIRBSvfJheZVh8k27g/tH5wpchZ47gxxatUKsVJ84P8 Me2S0RP9xtk3P14dVqTDJIhUC3k8JYdBiTTtk64EB5Dbq8sxEtjVb/68XDgTZKek te/vqWSW/KcduKEjsfjOwNSM9UbYrFOTbelac+mf/L+CluAJpYAlIhOMUP2afy5e tYIg6zK04pDNjPjizpfN3xrGX7NRY16kaafrdqJQixfmEVlMDN8FsXLWDweXWfMM XRh4vuAVb6tA9wBkPDhZAgMBAAGjggNMMIIDSDALBgNVHQ8EBAMCBLAwHQYDVR0l BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMHgGCSqGSIb3DQEJDwRrMGkwDgYIKoZI hvcNAwICAgCAMA4GCCqGSIb3DQMEAgIAgDALBglghkgBZQMEASowCwYJYIZIAWUD BAEtMAsGCWCGSAFlAwQBAjALBglghkgBZQMEAQUwBwYFKw4DAgcwCgYIKoZIhvcN AwcwHQYDVR0OBBYEFEaKqx6Auvu3fvHS6KqQl8KXoOoAMB8GA1UdIwQYMBaAFAhC 49tOEWbztQjFQNtVfDNGEYM4MIIBCgYDVR0fBIIBATCB/jCB+6CB+KCB9YZYaHR0 cDovL21zY3JsLm1pY3Jvc29mdC5jb20vcGtpL21zY29ycC9jcmwvTWljcm9zb2Z0 JTIwU2VjdXJlJTIwU2VydmVyJTIwQXV0aG9yaXR5KDgpLmNybIZWaHR0cDovL2Ny bC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL01pY3Jvc29mdCUyMFNlY3Vy ZSUyMFNlcnZlciUyMEF1dGhvcml0eSg4KS5jcmyGQWh0dHA6Ly9jb3JwcGtpL2Ny bC9NaWNyb3NvZnQlMjBTZWN1cmUlMjBTZXJ2ZXIlMjBBdXRob3JpdHkoOCkuY3Js MIG/BggrBgEFBQcBAQSBsjCBrzBeBggrBgEFBQcwAoZSaHR0cDovL3d3dy5taWNy b3NvZnQuY29tL3BraS9tc2NvcnAvTWljcm9zb2Z0JTIwU2VjdXJlJTIwU2VydmVy JTIwQXV0aG9yaXR5KDgpLmNydDBNBggrBgEFBQcwAoZBaHR0cDovL2NvcnBwa2kv YWlhL01pY3Jvc29mdCUyMFNlY3VyZSUyMFNlcnZlciUyMEF1dGhvcml0eSg4KS5j cnQwPwYJKwYBBAGCNxUHBDIwMAYoKwYBBAGCNxUIg8+JTa3yAoWhnwyC+sp9geH7 dIFPg8LthQiOqdKFYwIBZAIBCjAnBgkrBgEEAYI3FQoEGjAYMAoGCCsGAQUFBwMC MAoGCCsGAQUFBwMBMCYGA1UdEQQfMB2CG21hbmFnZW1lbnQuY29yZS53aW5kb3dz Lm5ldDANBgkqhkiG9w0BAQUFAAOCAQEAsqHBR/JxRnGQMTXxJzCau49dDgeum1JH heA38lzsoUaRELHxxrQZskjSqc0HrI7cnJPSipWQseDDwKtLwXzukCdZNk84u7xo uHa7/dmxo1m+z353HSvEr85ZE2mzwF6qmwGMmvvVzIJ94M8fcN55yoF64vQsAWFF k2QJC9ccb8eDoTs5NX4ntpz02xf8eEBQ5yKZySfi3+oFJEUnLmXcvHTTMl/1N/NI fWiKIZ9PDTBlPxL5kNJ/aDGIgiqCi7Vm7KfjvWSFhopUPtVeeItgW9wMLEkuQsw6 sViSbU50CMPWTJAslLZgCju6cxszgpLl19xrgNteHRw2HouwTTsJnA== -----END CERTIFICATE----- subject=/CN=management.core.windows.net issuer=/DC=com/DC=microsoft/DC=corp/DC=redmond/CN=Microsoft Secure Server Authority --- No client certificatee CA names sent --- SSL handshake has read 4691 bytes and written 450 bytes --- New, TLSv1/SSLv3, Cipher is AES128-SHA Server public key is 2048 bit Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES128-SHA Session-ID:  Session-ID-ctx: Master-Key:  Key-Arg : None Start Time: 1324443511 Timeout : 300 (sec) Verify return code: 20 (unable to get local issuer certificatee) --- GET //locations HTTP/1.1 Accept-Encoding: identity X-Ms-Version: 2011-10-01 Host: management.core.windows.net Connection: close 

Sous le plus récent et même un peu plus ancien (par exemple, le 0.9.8e d’Ubuntu10.04), OpenSSLs le serveur répond à la requête avec le prévu:

 Anywhere USAnywhere USSouth Central USSouth Central USAnywhere EuropeAnywhere EuropeWest EuropeWest EuropeAnywhere AsiaAnywhere AsiaSoutheast AsiaSoutheast AsiaEast AsiaEast AsiaNorth Central USNorth Central USNorth EuropeNorth Europe 

Mais avec OpenSSL 0.9.8l je n’ai rien.

Les opérations suivantes fonctionnent comme prévu avec IronPython 2.7.1 sous Windows 7 et CPython 2.6.6 sous OS X 10.6.8:

 import socket, ssl, sys sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('management.core.windows.net',443)) s = ssl.wrap_socket(sock, certfile=sys.argv[1]) s.send('GET /SUBSCRIPTION_ID/locations HTTP/1.1\r\nAccept-Encoding: identity\r\nX-Ms-Version: 2011-10-01\r\nHost: management.core.windows.net\r\nUser-Agent: Python-urllib/2.6\r\n\r\n') print(s.read(4096)) 

[REMARQUE: je passe MYKEYFILENAME.pem en tant que paramètre de ligne de commande.]

Happy Azure piratage!

Je ne suis pas un développeur Python. Mais j’ai été confronté à de nombreux problèmes lors de l’utilisation des services Azure sur iPhone et Windows Phone. Veuillez vous assurer de ce qui suit: