简体   繁体   English

Windows上针对Azure服务管理API的Python HTTPS失败

[英]Python HTTPS against Azure service management API fails on Windows

I've recently extended a Python API for the Windows Azure storage APIs (PyAzure) to include support for the service management APIs. 我最近为Windows Azure存储API(PyAzure)扩展了一个Python API,以包含对服务管理API的支持。 See https://github.com/bmb/pyazure . 请参阅https://github.com/bmb/pyazure

I'm using a HTTPSClientAuthHandler like the one suggested in using pyOpenSSL to create urllib custom opener . 我正在使用HTTPSClientAuthHandler,就像使用pyOpenSSL建议创建urllib自定义开启器一样 On Linux, with various versions of Python 2.6 and 2.7 this works well. 在Linux上,使用各种版本的Python 2.6和2.7,效果很好。 However, Windows is another story. 但是,Windows是另一个故事。 All requests against the Azure management host address fail with: 针对Azure管理主机地址的所有请求都失败:

[Errno 10054] An existing connection was forcibly closed by the remote host [Errno 10054]远程主机强行关闭现有连接

Which I think, is the socket errno 10054 "Connection reset by peer", in drag. 我认为,是套接字errno 10054“连接由同行重置”,在拖动。

This doesn't appear to be a problem in my API code (unless the client cert authentication method I'm using is bogus somehow), but something lower-level. 这在我的API代码中似乎不是问题(除非我使用的客户端证书身份验证方法是虚假的),但是更低级别的东西。 I can reproduce the issue without urllib2 or httplib by simply setting up an SSL socket and sending the same HTTP request down the pipe as urllib2 would, eg to list the valid Azure data centre locations: 我可以在没有urllib2或httplib的情况下重现问题,只需设置一个SSL套接字,然后像urllib2一样向管道发送相同的HTTP请求,例如列出有效的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

Replace SUBSCRIPTION_ID above, with your Azure subscription ID. 使用Azure订阅ID替换上面的SUBSCRIPTION_ID。 The exception is raised ~45s after calling SSLSocket.read. 调用SSLSocket.read后,异常会提高~45秒。 The cert is a properly formatted PEM file including both the private key and certificate, it was converted from the pfx (in Ubuntu 10.04) using: 证书是一个格式正确的PEM文件,包括私钥和证书,它是从pfx(在Ubuntu 10.04中)转换而来的,使用:

openssl pkcs12 -in pfxfile -out pemfile -nodes openssl pkcs12 -in pfxfile -out pemfile -nodes

I don't think it matters here, but I also tried unix2dos-ing the PEM file, to no avail though. 我认为这不重要,但我也试过unix2dos-ing PEM文件,但无济于事。 I get the same behaviour even when I don't provide any cert, but doing that on Linux results in a proper API error from the server: 即使我没有提供任何证书,我也会得到相同的行为,但在Linux上执行此操作会导致服务器出现正确的API错误:

'HTTP/1.1 403 Forbidden\\r\\nContent-Length: 0\\r\\nServer: Microsoft-HTTPAPI/2.0\\r\\nDate: Thu, 01 Dec 2011 13:59:29 GMT\\r\\nConnection: close\\r\\n\\r\\n' 'HTTP / 1.1 403禁止\\ r \\ n内容长度:0 \\ r \\ n服务器:Microsoft-HTTPAPI / 2.0 \\ r \\ n日期:2011年12月1日星期四13:59:29 GMT \\ r \\ n连接:关闭\\ r \\ n \\ r \\ N”

This has been independently verified by another person using Windows 7 (same as me). 这已由使用Windows 7的其他人(与我相同)独立验证。 It's not a client-side firewall issue - the same code works in a NAT-ed Linux VM running on the same host. 这不是客户端防火墙问题 - 相同的代码适用于在同一主机上运行的NAT-ed Linux VM。

I'm stumped. 我很难过。 Would really appreciate any help folks here might be able to provide... 真的很感激这里的帮助人们可以提供......

Update: This appears to be related to the underlying SSL implementation in Python. 更新:这似乎与Python中的基础SSL实现有关。 CPython 2.7.1 has the error behaviour as shown above, but I've since tested and had success with ActiveState Python (both 2.7 and 2.6), eg: 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>'

And as expected my API works too: 正如预期的那样,我的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']

The Lib\\ssl.py files in CPython2.7 and ActivePython2.7 are identical, so I guess this must be due to some difference in the underlying C libs, perhaps a bug in CPython. CPython2.7和ActivePython2.7中的Lib \\ ssl.py文件是相同的,所以我想这一定是由于底层C库中的一些差异,也许是CPython中的一个错误。 Any gurus out there? 那里有专家吗?

I haven't been able to pin down a definitive explanation for this, but after a bit of trial and error I'm confident of where the issue lays... 我无法确定这方面的明确解释,但经过一些试验和错误后,我对这个问题的位置充满信心......

Short answer: it's the ssl implementation in the http://www.python.org/ Windows bundle. 简短回答:这是http://www.python.org/Windows软件包中的ssl实现。 Use ActiveState Python instead. 请改用ActiveState Python。

Long Answer: The Windows CPython distributions available from http://www.python.org/download/ bundle quite an old version of OpenSSL (0.9.8l), compared with the ActiveState Python distributions which are based on CPython but (amongst other things) provide regular updates to 3rd party inclusions such as OpenSSL (currently 0.9.8r). 长答案:Windows CPython发行版可从http://www.python.org/download/捆绑得到相当旧版本的OpenSSL(0.9.8l),与基于CPython的ActiveState Python发行版相比,但(除其他外) )定期更新第三方内容,如OpenSSL(目前为0.9.8r)。

I downloaded Windows binaries of OpenSSL and tested via the openssl s_client interface, eg: 我下载了OpenSSL的Windows二进制文件,并通过openssl s_client接口进行了测试,例如:

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

The current version works, as expected. 正如预期的那样,当前版本有效。 Unfortunately it seems difficult to get one's hands on old OpenSSL binaries for Windows, perhaps not surprising given it is a security library... But anyway, I built 0.9.8l from source under Ubuntu 10.04 and found that it hangs after sending a HTTP request down the pipe, presumably the server silently dropped the connection for some reason: 不幸的是,似乎很难掌握用于Windows的旧OpenSSL二进制文件,也许这并不奇怪,因为它是一个安全库......但无论如何,我在Ubuntu 10.04下从源代码构建了0.9.8l并发现它在发送HTTP请求后挂起管道下方,可能服务器由于某种原因无声地丢弃了连接:

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

Under newer and even slightly older (eg, Ubuntu10.04's 0.9.8e) OpenSSLs the server responds to the request with the expected: 在较新的甚至稍微较旧的(例如,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>

But with OpenSSL 0.9.8l I get nothing. 但是使用OpenSSL 0.9.8l我什么都没得到。

The following works as expected using IronPython 2.7.1 on Windows 7 and CPython 2.6.6 on OS X 10.6.8: 以下使用Windows 7上的IronPython 2.7.1和OS X 10.6.8上的CPython 2.6.6进行预期工作:

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

[NOTE: I'm passing MYKEYFILENAME.pem as a command-line parameter.] [注意:我将MYKEYFILENAME.pem作为命令行参数传递。]

Happy Azure hacking! 快乐的Azure黑客!

I am not a Python developer .But I have faced so many issues when dealing with Azure services from iPhone and Windows Phone .Please ensure the following 我不是Python开发人员。但是我在处理来自iPhone和Windows Phone的Azure服务时遇到了很多问题。请确保以下内容

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM