2011-04-18 11 views
5

Çalıştığım bir API var. API, HTTPS ile güven altına alınır ve karşılıklı kimlik doğrulama/istemci sertifikaları kullanır. PEM dosyası ve CRT dosyam var. Bu istemci sertifikası ile bir HTTPS API olduğu için, bunun için bir açıcı uygulamış,İstemci sertifikalarını kullanan özel urllib açıcı

import settings 
from OpenSSL import SSL 
import socket 

def verify(conn, cert, errnum, depth, ok): 
    # This obviously has to be updated 
    print 'Got certificate: %s' % cert.get_subject() 
    return ok 

def password_callback(maxlen, verify, extra): 
     print (maxlen, verify, extra) 
     return settings.DEPOSIT_CODE 

context = SSL.Context(SSL.SSLv23_METHOD) 
context.set_verify(SSL.VERIFY_NONE, verify) 
context.set_passwd_cb(password_callback) 
context.use_certificate_file(settings.CLIENT_CERT_FILE) 
context.use_privatekey_file(settings.PEM_FILE) 

sock = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) 
sock.connect(("someserver.com",443)) 

http_get_request = """ 
GET/HTTP/1.1 

""" 
sock.write(http_get_request) 
print sock.recv(1000) 

Ama:

ben sorunum yok PyOpenSSL kullanarak, düzenli sunucusuna bağlanmak, burada kodudur

import settings 
import socket 
import urllib2 

def verify(conn, cert, errnum, depth, ok): 
    # This obviously has to be updated 
    print 'Got certificate: %s' % cert.get_subject() 
    return ok 

def password_callback(maxlen, verify, extra): 
     print (maxlen, verify, extra) 
     return settings.DEPOSIT_CODE 

class MyHTTPSConnection(httplib.HTTPSConnection): 
    def connect(self): 
     context = SSL.Context(SSL.SSLv23_METHOD) 
     context.set_passwd_cb(password_callback) 
     context.use_certificate_file(settings.CLIENT_CERT_FILE) 
     context.set_verify(SSL.VERIFY_NONE, verify) 
     context.use_privatekey_file(settings.PEM_FILE) 
     self.sock = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) 

class MyHTTPSHandler(urllib2.HTTPSHandler): 
    def https_open(self,req): 
     return self.do_open(MyHTTPSConnection,req) 

opener = urllib2.build_opener(urllib2.HTTPHandler,MyCHTTPSHandler) 
urllib2.install_opener(opener) 

f = urllib2.urlopen("https://sampleapiserver.com") 
print f.code 

ama ikinci kod çalıştırdığınızda, ben şu hatayı alıyorum: nasılsa değiştirilmiş kod burada

File "/usr/lib/python2.6/urllib2.py", line 126, in urlopen 
    return _opener.open(url, data, timeout) 
    File "/usr/lib/python2.6/urllib2.py", line 391, in open 
    response = self._open(req, data) 
    File "/usr/lib/python2.6/urllib2.py", line 409, in _open 
    '_open', req) 
    File "/usr/lib/python2.6/urllib2.py", line 369, in _call_chain 
    result = func(*args) 
    File "network.py", line 37, in https_open 
    return self.do_open(IRNICHTTPSConnection,req) 
    File "/usr/lib/python2.6/urllib2.py", line 1142, in do_open 
    h.request(req.get_method(), req.get_selector(), req.data, headers) 
    File "/usr/lib/python2.6/httplib.py", line 914, in request 
    self._send_request(method, url, body, headers) 
    File "/usr/lib/python2.6/httplib.py", line 951, in _send_request 
    self.endheaders() 
    File "/usr/lib/python2.6/httplib.py", line 908, in endheaders 
    self._send_output() 
    File "/usr/lib/python2.6/httplib.py", line 780, in _send_output 
    self.send(msg) 
    File "/usr/lib/python2.6/httplib.py", line 759, in send 
    self.sock.sendall(str) 
OpenSSL.SSL.Error: [('SSL routines', 'SSL_write', 'uninitialized')] 

Son olarak, yanlış bir şey yapıyorum? Aksi takdirde, lütfen bana hatayı anlamada yardımcı olun ...

Şerefe.

+0

Bunun bir HTTP API olduğunu söylediğiniz kısmı açıklayabilir misiniz, ancak HTTP protokolünden kurtulmak ister misiniz? – Keith

cevap

1

emin değilim - ama connect() yönteminde connect() çağrısı yapıyor eksik Bana öyle görünüyor: Ayrıca

self.sock.connect(("someserver.com",443)) 

httplib 'ın https işlemek için sarıcı sınıflar vardır SSL soketi, bu yüzden çalışmak için gerekli olabilir?

+0

Evet, dün yaptığım işte tam olarak bunu yaptım :) – Hosane

3

Burada gerçekten ihtiyacınız olmayan bir çok karmaşıklık ekliyorsunuz gibi görünüyor. Eğer sadece basit istemci sertifikası kimlik yapıyorsanız, muhtemelen aşağıdaki parçada uzak (source) alabilir:

import httplib 
import urllib2 

# HTTPS Client Auth solution for urllib2, inspired by 
# http://bugs.python.org/issue3466 
# and improved by David Norton of Three Pillar Software. In this 
# implementation, we use properties passed in rather than static module 
# fields. 
class HTTPSClientAuthHandler(urllib2.HTTPSHandler): 
    def __init__(self, key, cert): 
     urllib2.HTTPSHandler.__init__(self) 
     self.key = key 
     self.cert = cert 
    def https_open(self, req): 
     #Rather than pass in a reference to a connection class, we pass in 
     # a reference to a function which, for all intents and purposes, 
     # will behave as a constructor 
     return self.do_open(self.getConnection, req) 
    def getConnection(self, host): 
     return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert) 


cert_handler = HTTPSClientAuthHandler(settings.PEMFILE, settings.CLIENT_CERT_FILE) 
opener = urllib2.build_opener(cert_handler) 
urllib2.install_opener(opener) 

f = urllib2.urlopen("https://sampleapiserver.com") 
print f.code 

kaynak SudsClient bir sertifika-authenicated URL açacağı sağlama bağlamında kullanılmıştır Kurucu, bu yüzden onu çıkardım ve doğrudan bir açıcı yaptı.

+0

Bunun tek sorunu, bir şifre geri çağrısı yapamamanızdır (Python'un SSL desteğindeki yerleşik sürüm 3.3'e kadar bu özelliği içermemişti), Bu nedenle, istemci anahtarı parola korumalıysa, temel SSL kütüphanesinin kullanıcıyı uçbirimde istemeye çalışmasını engellemenin bir yolu yoktur. –

İlgili konular