2012-03-23 18 views
10

Đã dành một phần tốt trong một ngày cho việc này, và tôi thực sự là wit cuối cùng. Tôi có 1 máy "A" với cài đặt Python 2.6.6/2.7.2 và một máy "B" khác có cài đặt Python 2.6.7/2.7.2.Urllib.urlopen() hoạt động trên các url SSLv3 với Python 2.6.6 trên 1 máy, nhưng không phải với 2.6.7/2.7.2 trên một số khác

Trên máy A, tôi có thể nhận được trang web được mã hóa SSLv3 với urllib2.urlopen('https://fed.princeton.edu') sử dụng Python 2.6.6 nhưng không 2.7.2.

Trên máy B, tôi không thể truy cập trang web đó bằng phiên bản Python.

Bởi không thể có được, tôi có nghĩa là tôi nhận được lỗi:

Traceback: 
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/core/handlers/base.py" in get_response 
    111.       response = callback(request, *callback_args, **callback_kwargs) 
File "/usr/local/lib/python2.7/dist-packages/django_cas-2.0.3-py2.7.egg/django_cas/views.py" in login 
    78.   user = auth.authenticate(ticket=ticket, service=service) 
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/contrib/auth/__init__.py" in authenticate 
    55.    user = backend.authenticate(**credentials) 
File "/usr/local/lib/python2.7/dist-packages/django_cas-2.0.3-py2.7.egg/django_cas/backends.py" in authenticate 
    72.   username = _verify(ticket, service) 
File "/usr/local/lib/python2.7/dist-packages/django_cas-2.0.3-py2.7.egg/django_cas/backends.py" in _verify_cas2 
    46.  page = urlopen(url) 
File "/usr/lib/python2.7/urllib.py" in urlopen 
    84.   return opener.open(url) 
File "/usr/lib/python2.7/urllib.py" in open 
    205.     return getattr(self, name)(url) 
File "/usr/lib/python2.7/urllib.py" in open_https 
    435.    h.endheaders(data) 
File "/usr/lib/python2.7/httplib.py" in endheaders 
    954.   self._send_output(message_body) 
File "/usr/lib/python2.7/httplib.py" in _send_output 
    814.   self.send(msg) 
File "/usr/lib/python2.7/httplib.py" in send 
    776.     self.connect() 
File "/usr/lib/python2.7/httplib.py" in connect 
    1161.    self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) 
File "/usr/lib/python2.7/ssl.py" in wrap_socket 
    372.      ciphers=ciphers) 
File "/usr/lib/python2.7/ssl.py" in __init__ 
    134.     self.do_handshake() 
File "/usr/lib/python2.7/ssl.py" in do_handshake 
    296.   self._sslobj.do_handshake() 

Exception Type: IOError at /login 
Exception Value: [Errno socket error] [Errno 1] _ssl.c:503: error:140773F2:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert unexpected message 

Trước tiên, tôi đang bối rối rằng một cái gì đó mà làm việc trên một phiên bản Python trước đó không hoạt động trên sau này trên máy A Tôi cũng rất bối rối rằng một cái gì đó hoạt động trên 2.6.6 không hoạt động trên 2.6.7 (mặc dù trên các máy khác nhau). Tại sao điều này lại là?

Bây giờ tôi không chắc cấu hình cho Python là giống nhau trên cả hai, nhưng import _sslimport httplib; httplib.HTTPSConnection hoạt động với tất cả các phiên bản trên cả hai máy. Tôi cũng đã thử curl -v https://fed.princeton.eduopenssl fed.princeton.edu:https trên cả hai máy và tất cả các lệnh này đều hoạt động.

Tôi cũng đã thực hiện một số nghiên cứu và tìm thấy How to use urllib2 to get a webpage using SSLv3 encryption nơi tác giả dường như đã từ bỏ urllib cho libCurl (Tôi không thích vì tôi đang sử dụng django-cas, sử dụng urllib và tôi không muốn để fiddle với mã quá nhiều).


Note: Tôi chỉ thấy http://bugs.python.org/issue11220, và giải pháp bài cuối cùng cho phép tôi sử dụng urlopen để mở ra trang web. Nhưng làm thế nào tôi có thể sử dụng giải pháp của họ (mà có vẻ là sử dụng urllib2.install_opener(urllib2.build_opener(HTTPSHandlerV3()))?) Để giải quyết urlopen của tôi() trong django-cas?

+0

Có các phiên bản OpenSSL khác nhau trên hai hệ thống không? – larsks

Trả lời

6

Sau khi thử nghiệm thêm một chút, tôi đã chấp nhận rằng Python 2.6.6 là OK, nhưng 2.6.7+ có lỗi này không thể tìm nạp các trang được mã hóa SSLv3 qua urllib.urlopen().

Tôi đã giải quyết được sự cố của mình bằng cách sử dụng mẹo urllib2.install_opener tại http://bugs.python.org/issue11220 và django_cas đã chỉnh sửa để trình mở này được cài đặt trước bất kỳ cuộc gọi urlopen() nào.

0

Bạn có thể vá khỉ ssl.wrap_socket() bằng cách ghi đè tham số từ khóa ssl_version. Các mã sau đây có thể được sử dụng như là. Đặt giá trị này trước urlopen().

import ssl 
from functools import wraps 
def sslwrap(func): 
    @wraps(func) 
    def bar(*args, **kw): 
     kw['ssl_version'] = ssl.PROTOCOL_TLSv1 
     return func(*args, **kw) 
    return bar 

ssl.wrap_socket = sslwrap(ssl.wrap_socket) 

EDIT: Tôi đã cập nhật mã ở trên sau khi nhận ra rằng functools.partial không thực sự trả về hàm và sẽ không phù hợp trong trường hợp này. Chunky như nó có thể nhìn, mã trên vẫn là giải pháp tốt nhất mà tôi biết cho đến nay.

+3

Điều này không hiệu quả đối với tôi. – gozzilli

Các vấn đề liên quan