2010-03-02 16 views
8

Estoy usando httplib2 para realizar una solicitud desde mi servidor a otro servicio web. Queremos usar autenticación de certificado mutuo. Veo cómo usar un certificado para la conexión de salida (h.set_certificate), pero ¿cómo puedo verificar el certificado utilizado por el servidor de respuesta?Cómo hacer la autenticación de certificado mutuo con httplib2

This ticket parece indicar que httplib2 no lo hace por sí mismo, y tiene solo sugerencias vagas sobre dónde buscar.

¿Es posible? ¿Voy a tener que hackear en un nivel inferior?

Respuesta

5

Aquí está el código de mi compañero de trabajo de Dave St. Germain escribió para resolver el problema:

import ssl 
import socket 
from httplib2 import has_timeout 
import httplib2 
import socks 


class CertificateValidationError(httplib2.HttpLib2Error): 
    pass 


def validating_sever_factory(ca_cert_file): 
    # we need to define a closure here because we don't control 
    # the arguments this class is instantiated with 
    class ValidatingHTTPSConnection(httplib2.HTTPSConnectionWithTimeout): 

     def connect(self): 
      # begin copypasta from HTTPSConnectionWithTimeout 
      "Connect to a host on a given (SSL) port." 

      if self.proxy_info and self.proxy_info.isgood(): 
       sock = socks.socksocket(socket.AF_INET, socket.SOCK_STREAM) 
       sock.setproxy(*self.proxy_info.astuple()) 
      else: 
       sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

      if has_timeout(self.timeout): 
       sock.settimeout(self.timeout) 
      sock.connect((self.host, self.port)) 
      # end copypasta 


      try: 
       self.sock = ssl.wrap_socket(sock, 
          self.key_file, 
          self.cert_file, 
          cert_reqs=ssl.CERT_REQUIRED, 
          ca_certs=ca_cert_file 
          ) 
      except ssl.SSLError: 
       # we have to capture the exception here and raise later because 
       # httplib2 tries to ignore exceptions on connect 
       import sys 
       self._exc_info = sys.exc_info() 
       raise 
      else: 
       self._exc_info = None 

       # this might be redundant 
       server_cert = self.sock.getpeercert() 
       if not server_cert: 
        raise CertificateValidationError(repr(server_cert)) 

     def getresponse(self): 
      if not self._exc_info: 
       return httplib2.HTTPSConnectionWithTimeout.getresponse(self) 
      else: 
       raise self._exc_info[1], None, self._exc_info[2] 
    return ValidatingHTTPSConnection 


def do_request(url, 
     method='GET', 
     body=None, 
     headers=None, 
     keyfile=None, 
     certfile=None, 
     ca_certs=None, 
     proxy_info=None, 
     timeout=30): 
    """ 
    makes an http/https request, with optional client certificate and server 
    certificate verification. 
    returns response, content 
    """ 
    kwargs = {} 
    h = httplib2.Http(proxy_info=proxy_info, timeout=timeout) 
    is_ssl = url.startswith('https') 
    if is_ssl and ca_certs: 
     kwargs['connection_type'] = validating_sever_factory(ca_certs) 

    if is_ssl and keyfile and certfile: 
     h.add_certificate(keyfile, certfile, '') 
    return h.request(url, method=method, body=body, headers=headers, **kwargs) 
3

tal vez las cosas han cambiado desde su pregunta, yo soy capaz de hacer la autenticación mutua con httplib2 v0.7, como a continuación:

import httplib2 

h=httplib2.Http(ca_certs='ca.crt') 
h.add_certificate(key='client_private_key.pem', cert='cert_client.pem', domain='') 
try: resp, cont = h.request('https://mytest.com/cgi-bin/test.cgi') 
except Exception as e: print e 

Nota domain='' el argumento, esta es la única manera de que pudiera hacer que funcione

+2

de acuerdo con [este enlace] (http://nullege.com/codes/search/httplib2 .Http.add_certificate), 'domain' debe ser solo un nombre de host y puerto. – arturo

Cuestiones relacionadas