Commit dd418e8c authored by Alejandro Alvarez Ayllon's avatar Alejandro Alvarez Ayllon
Browse files

Switched to pycurl. Caching password so it is asked only once.

parent bc2f7ef1
......@@ -56,6 +56,7 @@ Summary: FTS3 Rest Interface CLI
Group: Applications/Internet
Requires: python-fts
Requires: python-pycurl
%description cli
Command line utilities for the FTS3 REST interface
......
from datetime import datetime
from M2Crypto import X509, RSA, EVP, BIO
import getpass
import json
import logging
import os
......@@ -37,6 +38,11 @@ class Context(object):
else:
self.logger = logging.getLogger()
def _read_passwd_from_stdin(self, *args, **kwargs):
if not self.passwd:
self.passwd = getpass.getpass('Private key password: ')
return self.passwd
def _set_x509(self, ucert, ukey):
if not ucert:
if 'X509_USER_PROXY' in os.environ:
......@@ -57,7 +63,7 @@ class Context(object):
if not_after.get_datetime() < datetime.now(pytz.UTC):
raise Exception("Proxy expired!")
self.rsa_key = RSA.load_key(ukey)
self.rsa_key = RSA.load_key(ukey, self._read_passwd_from_stdin)
self.evp_key = EVP.PKey()
self.evp_key.assign_rsa(self.rsa_key)
......@@ -82,10 +88,12 @@ class Context(object):
return endpoint_info
def __init__(self, endpoint, ucert=None, ukey=None, logger=None):
self.passwd = None
self._set_logger(logger)
self._set_endpoint(endpoint)
self._set_x509(ucert, ukey)
self._requester = RequestFactory(self.ucert, self.ukey)
self._requester = RequestFactory(self.ucert, self.ukey, passwd=self.passwd)
self.endpoint_info = self._validate_endpoint()
# Log obtained information
self.logger.debug("Using endpoint: %s" % self.endpoint_info['url'])
......
......@@ -46,7 +46,6 @@ class Delegator(object):
proxy_subject.add_entry_by_txt('commonName', 0x1000, 'proxy', -1, -1, 0)
proxy = X509.X509()
proxy.set_version(2)
proxy.set_subject(proxy_subject)
proxy.set_serial_number(int(time.time()))
proxy.set_version(x509_request.get_version())
......@@ -75,6 +74,7 @@ class Delegator(object):
if any_rfc_proxies:
raise NotImplementedError('RFC proxies not supported yet')
proxy.set_version(2)
proxy.sign(self.context.evp_key, 'sha1')
return proxy
......
import httplib
import sys
import urllib2
import pycurl
from exceptions import *
class HTTPSWithCertHandler(urllib2.HTTPSHandler):
def __init__(self, cert, key):
urllib2.HTTPSHandler.__init__(self)
self.cert = cert
self.key = key
def https_open(self, req):
return self.do_open(self.getConnection, req)
def getConnection(self, host, timeout=1000):
return httplib.HTTPSConnection(host, cert_file=self.cert,
key_file=self.key)
from StringIO import StringIO
class RequestFactory(object):
def __init__(self, ucert, ukey, cafile=None, capath=None, verify=False):
def __init__(self, ucert, ukey, cafile=None, capath=None, passwd=None, verify=False):
self.ucert = ucert
self.ukey = ukey
self.passwd = passwd
self.verify = verify
......@@ -36,28 +22,67 @@ class RequestFactory(object):
else:
self.capath = '/etc/grid-security/certificates'
def _handleException(self, url, e):
f = open('/tmp/request-error.html', 'w')
print >>f, e.read()
del f
if e.code == 400:
raise ClientError(str(e))
elif e.code >= 401 and e.code <= 403:
def _handle_error(self, url, code):
if code == 400:
raise ClientError('Bad request')
elif code >= 401 and code <= 403:
raise Unauthorized()
elif e.code == 404:
elif code == 404:
raise NotFound(url)
elif e.code > 404 and e.code < 500:
raise ClientError(str(e))
elif e.code >= 500:
raise ServerError(str(e))
def method(self, method, url, body=None, headers={}):
opener = urllib2.build_opener(HTTPSWithCertHandler(self.ucert,
self.ukey))
try:
request = urllib2.Request(url, headers=headers, data=body)
request.get_method = lambda: method
response = opener.open(request)
return response.read()
except urllib2.HTTPError, e:
self._handleException(url, e)
elif code > 404 and code < 500:
raise ClientError(str(code))
elif code >= 500:
raise ServerError(str(code))
def _receive(self, data):
self._response += data
return len(data)
def _send(self, len):
return self._input.read(len)
def _ioctl(self, cmd):
if cmd == pycurl.IOCMD_RESTARTREAD:
self._input.seek(0)
def method(self, method, url, body=None, headers=None):
handle = pycurl.Curl()
handle.setopt(pycurl.SSL_VERIFYPEER, self.verify)
handle.setopt(pycurl.SSL_VERIFYHOST, self.verify)
handle.setopt(pycurl.CAPATH, self.capath)
handle.setopt(pycurl.CAINFO, self.cafile)
handle.setopt(pycurl.SSLCERT, self.ucert)
handle.setopt(pycurl.SSLKEY, self.ukey)
if self.passwd:
handle.setopt(pycurl.SSLKEYPASSWD, self.passwd)
if method == 'GET':
handle.setopt(pycurl.HTTPGET, True)
elif method == 'HEAD':
handle.setopt(pycurl.NOBODY, True)
elif method == 'POST':
handle.setopt(pycurl.POST, True)
elif method == 'PUT':
handle.setopt(pycurl.UPLOAD, True)
else:
handle.setopt(pycurl.CUSTOMREQUEST, method)
if headers:
handle.setopt(pycurl.HTTPHEADER, map(lambda (k, v): "%s: %s" % (k, v), headers.iteritems()))
handle.setopt(pycurl.URL, str(url))
self._response = ''
handle.setopt(pycurl.WRITEFUNCTION, self._receive)
if body is not None:
self._input = StringIO(body)
handle.setopt(pycurl.INFILESIZE, len(body))
handle.setopt(pycurl.POSTFIELDSIZE, len(body))
handle.setopt(pycurl.READFUNCTION, self._send)
handle.setopt(pycurl.IOCTLFUNCTION, self._ioctl)
handle.perform()
self._handle_error(url, handle.getinfo(pycurl.HTTP_CODE))
return self._response
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment