2011-04-18 4 views
5

J'ai une API avec laquelle je dois travailler. L'API est sécurisée par HTTPS et utilise des certificats d'authentification mutuelle/client. J'ai un fichier PEM et un fichier CRT.Opérateur urllib personnalisé utilisant des certificats clients

Lorsque je me connecte au serveur régulièrement, en utilisant pyopenssl Je n'ai pas de problème, voici le code:

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) 

Mais, parce que c'est une API HTTPS avec certificat client, je l'ai mis en place un dispositif d'ouverture pour elle , le code est modifié en quelque sorte ici:

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 

mais quand je lance le second code, je reçois l'erreur suivante:

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

Enfin, est-ce que je fais quelque chose de mal? Si non, s'il vous plaît aidez-moi à comprendre l'erreur ...

Cheers.

+0

Pourriez-vous clarifier la partie où vous dites qu'il s'agit d'une API HTTP, mais que vous voulez vous débarrasser du protocole HTTP? – Keith

Répondre

1

Je ne suis pas sûr - mais il me semble que vous manquez de faire le connect() dans la méthode connect():

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

également httplib « s manipulation https a des classes wrapper pour la Socket SSL, alors peut-être que ceux-ci sont nécessaires pour que cela fonctionne?

+0

Ouais, c'est exactement ce que j'ai fait hier et l'ai fait réparer :) – Hosane

3

Il semble que vous ajoutiez beaucoup de complexité ici dont vous n'avez pas vraiment besoin. Si vous êtes juste faire simple, l'authentification par certificat client, vous pouvez probablement vous en sortir de l'extrait suivant (source):

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 

La source a été utilisée dans le contexte de fournir une URL cert-authenicated ouvre la SudsClient constructeur, donc je l'ai dépouillé et fait un ouvreur direct.

+0

Le seul problème avec ceci est que vous ne pouvez pas définir un rappel de mot de passe (le support SSL intégré de Python n'avait pas cette facilité jusqu'à la version 3.3) Par conséquent, si la clé du client est protégée par mot de passe, il n'y a aucun moyen d'empêcher la bibliothèque SSL sous-jacente d'essayer d'inviter l'utilisateur sur le terminal. –

Questions connexes