SSL-соединение с использованием сертификата.pem с Python
Я пытаюсь установить успешную связь через HTTPS-соединение с использованием аутентификации. Я использую Python 2.7 с Django 1.4 на Ubuntu 12.04.
Документация API, которой я следую, имеет особые требования для аутентификации. В том числе Authentication
заголовок вы найдете ниже и отправка информации о сертификате.
Это код:
import httplib
import base64
HOST = 'some.host.com'
API_URL = '/some/api/path'
username = '1234'
password = '5678'
auth_value = base64.b64encode('WS{0}._.1:{1}'.format(username, password))
path = os.path.join(os.path.dirname(__file__), 'keys/')
pem_file = '{0}WS{1}._.1.pem'.format(path, username)
xml_string = '<some><xml></xml><stuff></stuff></some>'
headers = { 'User-Agent' : 'Rico',
'Content-type' : 'text/xml',
'Authorization' : 'Basic {0}'.format(auth_value),
}
conn = httplib.HTTPSConnection(HOST, cert_file = pem_file)
conn.putrequest("POST", API_URL, xml_string, headers)
response = conn.getresponse()
Я получаю следующую ошибку:
Traceback:
File "/usr/local/lib/python2.7/dist-packages/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/views/decorators/csrf.py" in wrapped_view
77. return view_func(*args, **kwargs)
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in processPayment
37. processCreditCard = ProcessCreditCard(token, postHandling)
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in __init__
75. self.processGateway()
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in processGateway
95. gateway = Gateway(self)
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in __init__
37. self.postInfo()
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in postInfo
245. response = conn.getresponse()
File "/usr/lib/python2.7/httplib.py" in getresponse
1018. raise ResponseNotReady()
Exception Type: ResponseNotReady at /processPayment/
Exception Value:
Почему я получаю эту ошибку?
ОБНОВЛЕНИЕ 1: я использую .pem
файл, который они мне дали (Link Point Gateway), но прочитал, что файл сертификата должен содержать как сертификат, так и закрытый ключ RSA. Это верно? Я пытался отправить .pem
Файл, содержащий оба и получил следующую ошибку:
Traceback:
File "/usr/local/lib/python2.7/dist-packages/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/views/decorators/csrf.py" in wrapped_view
77. return view_func(*args, **kwargs)
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in processPayment
37. processCreditCard = ProcessCreditCard(token, postHandling)
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in __init__
75. self.processGateway()
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in processGateway
95. gateway = Gateway(self)
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in __init__
37. self.postInfo()
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in postInfo
251. conn.request('POST', self.API_URL, self.xml_string, headers)
File "/usr/lib/python2.7/httplib.py" in request
958. self._send_request(method, url, body, headers)
File "/usr/lib/python2.7/httplib.py" in _send_request
992. self.endheaders(body)
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
381. ciphers=ciphers)
File "/usr/lib/python2.7/ssl.py" in __init__
141. ciphers)
Exception Type: SSLError at /processPayment/
Exception Value: [Errno 336265225] _ssl.c:351: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
Я не могу сказать, является ли это шагом вперед или назад.
ОБНОВЛЕНИЕ 2: я пытался передать и файл сертификата и файл ключа при создании объекта подключения.
conn = httplib.HTTPSConnection(HOST, cert_file = pem_file, key_file = key_file)
Я получаю следующую ошибку:
Traceback:
File "/usr/local/lib/python2.7/dist-packages/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/views/decorators/csrf.py" in wrapped_view
77. return view_func(*args, **kwargs)
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in processPayment
37. processCreditCard = ProcessCreditCard(token, postHandling)
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in __init__
75. self.processGateway()
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in processGateway
95. gateway = Gateway(self)
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in __init__
37. self.postInfo()
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in postInfo
252. conn.request('POST', self.API_URL, self.xml_string, headers)
File "/usr/lib/python2.7/httplib.py" in request
958. self._send_request(method, url, body, headers)
File "/usr/lib/python2.7/httplib.py" in _send_request
992. self.endheaders(body)
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
381. ciphers=ciphers)
File "/usr/lib/python2.7/ssl.py" in __init__
141. ciphers)
Exception Type: SSLError at /processPayment/
Exception Value: [Errno 336265225] _ssl.c:351: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
Если я пытаюсь объединить файл сертификата и файл ключа и отправить его в качестве аргумента сертификата, я получаю ту же ошибку.
1 ответ
Казалось бы, некоторые библиотеки "более высокого уровня" в Python не оборудованы для обработки такого типа соединения аутентификации. После многих дней попыток я наконец смог найти решение, опускающееся до уровня сокетов.
host = 'some.host.com'
service = '/some/api/path'
port = 443
# Build the authorization info
username = '1234'
password = '5678'
path = '/path/to/key/files/'
pem_file = '{0}WS{1}._.1.pem'.format(path, username)
key_file = '{0}WS{1}._.1.key'.format(path, username)
auth = base64.b64encode('WS{0}._.1:{1}'.format(username, password))
## Create the header
http_header = "POST {0} HTTP/1.0\nHost: {1}\nContent-Type: text/xml\nAuthorization: Basic {2}\nContent-Length: {3}\n\n"
req = http_header.format(service, host, auth, len(xml_string)) + xml_string
## Create the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn = ssl.wrap_socket(sock, keyfile = key_file, certfile = pem_file)
conn.connect((host, port))
conn.send(req)
response = ''
while True:
resp = conn.recv()
response += resp
if (resp == ''):
break
Я надеюсь, что кто-то найдет это полезным. Эта конкретная реализация должна была взаимодействовать с Link Point Gateway с Python (не поддерживается First Data (Link Point)). Разговор о кошмаре, которым был весь этот проект. ха-ха
В любом случае, если у вас возникли проблемы с использованием Link Point, имейте в виду, что .key
файла, который они вам предоставляют, недостаточно для создания соединения в Python.
openssl rsa -in orig_file.key -out new_file.key
Затем используйте new_file.key
вместо.