Python HTTPS против API управления сервисами Azure не работает в Windows

Недавно я расширил API Python для API хранения Windows Azure (PyAzure), чтобы включить поддержку API-интерфейсов управления сервисами. См. https://github.com/bmb/pyazure.

Я использую HTTPSClientAuthHandler, подобный предложенному в используя pyOpenSSL для создания пользовательского открывателя urllib. В Linux с различными версиями Python 2.6 и 2.7 это работает хорошо. Однако Windows - это еще одна история. Все запросы против адреса узла управления Azure не выполняются:

[Errno 10054] Существующее соединение было принудительно закрыто удаленным хостом

Я думаю, что это сокет errno 10054 "Connection reset by peer", в режиме перетаскивания.

Это не похоже на проблему в моем коде API (если только метод проверки подлинности сертификата клиента, который я использую, не является фиктивным), а что-то более низкое. Я могу воспроизвести проблему без urllib2 или httplib, просто установив SSL-сокет и отправив тот же HTTP-запрос по каналу, что и urllib2, например. для перечисления действительных местоположений центров данных Azure:

>>> 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\\azure\\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\azure\pyazure\<ipython-input-63-3306c981d8a7>
in <module>()
----> 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

Замените SUBSCRIPTION_ID выше, с вашим идентификатором подписки Azure. Исключение составляет ~ 45 с после вызова SSLSocket.read. Сертификат - это правильно отформатированный файл PEM, включающий как закрытый ключ, так и сертификат, он был преобразован из pfx (в Ubuntu 10.04), используя:

openssl pkcs12 -in pfxfile -out pemfile -nodes

Я не думаю, что это имеет значение здесь, но я также пробовал unix2dos-ing файл PEM, но безрезультатно. Я получаю такое же поведение, даже когда я не предоставляю никакого сертификата, но при этом в Linux возникает правильная ошибка API с сервера:

'HTTP/1.1 403 Запрещено \r\nContent-Length: 0\r\nServer: Microsoft-HTTPAPI/2.0\r\nДата: Чт, 01 Дек 2011 13:59:29 GMT\r\nСоединение: close\г\п\г\п '

Это независимое подтверждение другим человеком, использующим Windows 7 (так же, как и я). Это не проблема брандмауэра на стороне клиента - тот же код работает в виртуальной виртуальной машине Linux, работающей на одном узле.

Я в тупике. Было бы действительно признательно, что любая помощь здесь может быть предоставлена ​​...

Update: Это похоже на базовую реализацию SSL в Python. CPython 2.7.1 имеет поведение ошибки, как показано выше, но с тех пор я тестировал и добился успеха с помощью ActiveState Python (как 2.7, так и 2.6), например:

>>> 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\\azure\\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\n<Locations xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Location><Name>Anywhere US</Name><DisplayName>Anywhere US</DisplayName></Location><Location><Name>South Central US</Name><DisplayName>South Central US</DisplayName></Location><Location><Name>North Central US</Name><DisplayName>North Central US</DisplayName></Location><Location><Name>Anywhere Europe</Name><DisplayName>Anywhere Europe</DisplayName></Location><Location><Name>North Europe</Name><DisplayName>North Europe</DisplayName></Location><Location><Name>West Europe</Name><DisplayName>West Europe</DisplayName></Location><Location><Name>Anywhere Asia</Name><DisplayName>Anywhere Asia</DisplayName></Location><Location><Name>Southeast Asia</Name><DisplayName>Southeast Asia</DisplayName></Location><Location><Name>East Asia</Name><DisplayName>East Asia</DisplayName></Location></Locations>'

И как и ожидалось, мой API тоже работает:

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 pyazure import pyazure
>>> pa = pyazure.PyAzure(subscription_id=SUBSCRIPTION_ID, management_cert_path='c:\\users\\blair\\research\\clouds\\azure\\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']

Файлы Lib\ssl.py в CPython2.7 и ActivePython2.7 идентичны, поэтому я предполагаю, что это должно быть связано с некоторой разницей в базовых C libs, возможно, с ошибкой в ​​CPython. Любые гуру?

Ответы

Ответ 1

Я не смог определить окончательное объяснение этого, но после нескольких проб и ошибок я уверен, где проблема...

Короткий ответ: это реализация ssl в http://www.python.org/ комплекте Windows. Вместо этого используйте ActiveState Python.

Длинный ответ: Распределения Windows CPython, доступные из http://www.python.org/download/, содержат довольно старую версию OpenSSL (0.9.8l) по сравнению с дистрибутивами ActiveState Python, которые основаны на CPython, но (среди прочего) регулярно предоставляют обновления для сторонних включений, таких как OpenSSL (в настоящее время 0.9.8r).

Я загрузил двоичные файлы Windows OpenSSL и протестирован через интерфейс openssl s_client, например:

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

Текущая версия работает, как и ожидалось. К сожалению, трудно получить одну руку на старые двоичные файлы OpenSSL для Windows, возможно, это не удивительно, учитывая, что это библиотека безопасности... Но в любом случае я построил 0.9.8l из источника под Ubuntu 10.04 и обнаружил, что он зависает после отправки HTTP-запроса по трубе, предположительно, сервер почему-то молча отключил соединение:

[email protected]:~/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 certificate
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 certificate
-----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 certificate 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: <SNIP>
    Session-ID-ctx: 
    Master-Key: <SNIP>
    Key-Arg   : None
    Start Time: 1324443511
    Timeout   : 300 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
---
GET /<SUBSCRIPTION_ID>/locations HTTP/1.1
Accept-Encoding: identity
X-Ms-Version: 2011-10-01
Host: management.core.windows.net
Connection: close

Под более новыми и даже немного более старыми (например, Ubuntu10.04 0.9.8e) OpenSSL сервер отвечает на запрос ожидаемым:

<Locations xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Location><Name>Anywhere US</Name><DisplayName>Anywhere US</DisplayName></Location><Location><Name>South Central US</Name><DisplayName>South Central US</DisplayName></Location><Location><Name>Anywhere Europe</Name><DisplayName>Anywhere Europe</DisplayName></Location><Location><Name>West Europe</Name><DisplayName>West Europe</DisplayName></Location><Location><Name>Anywhere Asia</Name><DisplayName>Anywhere Asia</DisplayName></Location><Location><Name>Southeast Asia</Name><DisplayName>Southeast Asia</DisplayName></Location><Location><Name>East Asia</Name><DisplayName>East Asia</DisplayName></Location><Location><Name>North Central US</Name><DisplayName>North Central US</DisplayName></Location><Location><Name>North Europe</Name><DisplayName>North Europe</DisplayName></Location></Locations>

Но с OpenSSL 0.9.8l я ничего не получаю.

Ответ 2

Следующее работает как ожидалось, используя IronPython 2.7.1 для Windows 7 и CPython 2.6.6 для 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))

[ПРИМЕЧАНИЕ: я передаю MYKEYFILENAME.pem в качестве параметра командной строки.]

Счастливый хакерский хакер!

Ответ 3

Я не разработчик Python. Но я столкнулся с таким количеством проблем при работе с Azure-сервисами с iPhone и Windows Phone. Пожалуйста, убедитесь, что

  • Сертификат верен. сертификат должен содержать правильный URL-адрес, который вы нажимаете.
  • Есть ли способ исключить проверку сертификата в python. как в .net? http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors Если это так, убедитесь, что URL-адрес работает.
  • Убедитесь, что сертификат, который вы принимаете, находится в правом хранилище сертификатов.