我使用以下代码与ssl服务器执行和ssl握手和证书验证。
import ssl
import socket
s = socket.socket()
print "connecting..."
#logging.debug("Connecting")
# Connect with SSL mutual authentication
# We only trust our server's CA, and it only trusts user certificates signed by it
c = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_SSLv3, ca_certs='ca.crt',
certfile='user.crt', keyfile='user.key')
c.connect((constants.server_addr, constants.port))
我能够获得与服务器的连接,并且证书已正确验证,但是,我不知道该怎么做。我需要在套接字上执行https操作,包括将XML发布到REST API。我该怎么做?
答案 0 :(得分:1)
您可以使用wrap_socket
代码扩展httplib.HTTPConnection
,如this answer中所述。
(我仍然考虑使用像PycURL这样的东西,因为我已经在your previous question中回答了。)
答案 1 :(得分:0)
您可能希望从urllib2.urlopen
:http://docs.python.org/library/urllib2.html#urllib2.urlopen
这可以处理https网址,抓取,发布等。您无需直接在低级socket
或ssl
对象上工作。但是,如果你正在使用Python 2.x,那么HTTPS连接将不会对服务器端证书进行任何验证,这看起来就像你需要的那样(这很好)。不过,Python 3的urllib
确实可以做到这一点。
如果您使用的是Python 2,那么您有几个选择。一个是子类urllib2.HTTPSHandler
,以便它在其套接字上进行适当的验证。另一种方法是实现您自己需要的HTTP协议位(不推荐)。您也可以正常实例化各种urllib2
和httplib
对象,然后只需分配已经过身份验证的ssl套接字来代替它们正在使用的套接字,尽管您需要非常小心它们的状态不要搞砸了。但是,标准库中的源代码非常易读,以防您需要像这样修补。
答案 2 :(得分:0)
这正是我在项目中所做的。这是我在项目中使用的REST客户端模块。它已经过修改以满足我的需求,但我认为您可能会发现它也很有用。它需要httplib2:http://pypi.python.org/pypi/httplib2
"""
client.py
---------
Modified to allow validation server's certificate with external cacert list.
-- Arif Widi Nugroho <arif@sainsmograf.com>
Copyright (C) 2008 Benjamin O'Steen
This file is part of python-fedoracommons.
python-fedoracommons is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python-fedoracommons is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with python-fedoracommons. If not, see <http://www.gnu.org/licenses/>.
"""
__license__ = 'GPL http://www.gnu.org/licenses/gpl.txt'
__author__ = "Benjamin O'Steen <bosteen@gmail.com>, Arif Widi Nugroho <arif@sainsmograf.com>"
__version__ = '0.1'
import httplib2
import urlparse
import urllib
import base64
from base64 import encodestring
from mime_types import *
import mimetypes
from cStringIO import StringIO
class Connection(object):
def __init__(self, base_url, username=None, password=None, cache=None, ca_certs=None, user_agent_name=None):
self.base_url = base_url
self.username = username
m = MimeTypes()
self.mimetypes = m.get_dictionary()
self.url = urlparse.urlparse(base_url)
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(base_url)
self.scheme = scheme
self.host = netloc
self.path = path
if user_agent_name is None:
self.user_agent_name = 'Basic Agent'
else:
self.user_agent_name = user_agent_name
# Create Http class with support for Digest HTTP Authentication, if necessary
# self.h = httplib2.Http(".cache")
self.h = httplib2.Http(cache=cache, ca_certs=ca_certs)
self.h.follow_all_redirects = True
if username and password:
self.h.add_credentials(username, password)
def request_get(self, resource, args = None, headers={}):
return self.request(resource, "get", args, headers=headers)
def request_delete(self, resource, args = None, headers={}):
return self.request(resource, "delete", args, headers=headers)
def request_head(self, resource, args = None, headers={}):
return self.request(resource, "head", args, headers=headers)
def request_post(self, resource, args = None, body = None, filename=None, headers={}):
return self.request(resource, "post", args , body = body, filename=filename, headers=headers)
def request_put(self, resource, args = None, body = None, filename=None, headers={}):
return self.request(resource, "put", args , body = body, filename=filename, headers=headers)
def get_content_type(self, filename):
extension = filename.split('.')[-1]
guessed_mimetype = self.mimetypes.get(extension, mimetypes.guess_type(filename)[0])
return guessed_mimetype or 'application/octet-stream'
def request(self, resource, method = "get", args = None, body = None, filename=None, headers={}):
params = None
path = resource
headers['User-Agent'] = self.user_agent_name
BOUNDARY = u'00hoYUXOnLD5RQ8SKGYVgLLt64jejnMwtO7q8XE1'
CRLF = u'\r\n'
if filename and body:
#fn = open(filename ,'r')
#chunks = fn.read()
#fn.close()
# Attempt to find the Mimetype
content_type = self.get_content_type(filename)
headers['Content-Type']='multipart/form-data; boundary='+BOUNDARY
encode_string = StringIO()
encode_string.write(CRLF)
encode_string.write(u'--' + BOUNDARY + CRLF)
encode_string.write(u'Content-Disposition: form-data; name="file"; filename="%s"' % filename)
encode_string.write(CRLF)
encode_string.write(u'Content-Type: %s' % content_type + CRLF)
encode_string.write(CRLF)
encode_string.write(body)
encode_string.write(CRLF)
encode_string.write(u'--' + BOUNDARY + u'--' + CRLF)
body = encode_string.getvalue()
headers['Content-Length'] = str(len(body))
elif body:
if not headers.get('Content-Type', None):
headers['Content-Type']='text/xml'
headers['Content-Length'] = str(len(body))
else:
headers['Content-Type']='text/xml'
if method.upper() == 'POST':
headers['Content-Type']='application/x-www-form-urlencoded'
if args:
path += u"?" + urllib.urlencode(args)
request_path = []
if self.path != "/":
if self.path.endswith('/'):
request_path.append(self.path[:-1])
else:
request_path.append(self.path)
if path.startswith('/'):
request_path.append(path[1:])
else:
request_path.append(path)
resp, content = self.h.request(u"%s://%s%s" % (self.scheme, self.host, u'/'.join(request_path)), method.upper(), body=body, headers=headers )
return {u'headers':resp, u'body':content.decode('UTF-8')}
示例用法(如果服务器证书未由指定的ca签名,则连接将失败):
c = client.Connection('https://localhost:8000', certs='/path/to/cacert.pem')
# now post some data to the server
response = c.request_post('rest/path/', body=some_urlencoded_data)
if response['headers']['status'] == '200':
# do something...