2012-03-23 13 views
10

Spędziłem dobrą część dnia na tym, i jestem realny na mój koniec dowcipu. Mam 1 komputer "A" z zainstalowanym Pythonem 2.6.6/2.7.2 i inną maszynę "B" z zainstalowanym Pythonem 2.6.7/2.7.2.Urllib.urlopen() działa na adresach URL SSLv3 z Pythonem 2.6.6 na 1 komputerze, ale nie z 2.6.7/2.7.2 na innym

Na maszynie, można uzyskać na stronie internetowej SSLv3 szyfrowane z użyciem Pythona 2.6.6 urllib2.urlopen('https://fed.princeton.edu') ale nie 2.7.2.

Na maszynie B, Nie mogę pobrać tej witryny przy użyciu wersji Python.

By nie może dostać, to znaczy, że pojawia się błąd:

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 

pierwsze, jestem zdezorientowany, że coś, co działa na starszej wersji Pythona nie działa na później na maszynie Jestem również bardzo zdezorientowany, że coś, co działa w wersji 2.6.6, nie działa w wersji 2.6.7 (choć na różnych komputerach). Dlaczego miałoby to być?

Teraz nie jestem pewien, czy konfiguracja dla Pythona jest dokładnie taka sama w obu, ale import _ssl i import httplib; httplib.HTTPSConnection działa dla wszystkich wersji na obu komputerach. Próbowałem również curl -v https://fed.princeton.edu i openssl fed.princeton.edu:https na obu komputerach i wszystkie te polecenia działają.

Ja również zrobić rozeznanie i okazało How to use urllib2 to get a webpage using SSLv3 encryption gdzie autor wydawało się, że zrezygnowali z urllib dla libCurl (wolałbym nie, ponieważ używam Django CAS, który używa urllib i nie chcę zbyt wiele skrzywdzić tym kodem).


Uwaga: Właśnie znalazłem http://bugs.python.org/issue11220, a rozwiązanie poprzednim poście pozwala mi korzystać urlopen aby otworzyć stronę internetową. Ale jak mogę użyć ich rozwiązania (które zdaje się używać urllib2.install_opener(urllib2.build_opener(HTTPSHandlerV3()))?), Aby rozwiązać mój urlopen() w django-cas?

+0

Czy są różne wersje OpenSSL na obu systemach? – larsks

Odpowiedz

6

Po nieco bardziej eksperymentującym po prostu zaakceptowałem, że Python 2.6.6 jest OK, ale 2.6.7+ ma ten błąd, że nie może pobrać stron zaszyfrowanych przez SSLv3 za pośrednictwem urllib.urlopen().

Rozwiązałem swój problem, używając po prostu sztuczki urllib2.install_opener pod adresem http://bugs.python.org/issue11220 i zmodyfikowałem django_cas tak, aby ten opener został zainstalowany przed każdym połączeniem urlopen().

0

Możesz ssl.wrap_socket (małp-łatać małpkę) przesłonić parametr słowa kluczowego ssl_version. Poniższy kod może być użyty tak jak jest. Umieść to przed 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: I został uaktualniony kod powyżej po zdając sobie sprawę, że functools.partial faktycznie nie zwróci funkcję, a nie byłoby odpowiednie w tym przypadku. Chunky, jak mogłoby się wydawać, powyższy kod jest nadal najlepszym rozwiązaniem, jakie znam do tej pory.

+3

To nie działa dla mnie. – gozzilli

Powiązane problemy