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):
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() <
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()
......@@ -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_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()
......@@ -75,6 +74,7 @@ class Delegator(object):
if any_rfc_proxies:
raise NotImplementedError('RFC proxies not supported yet')
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):
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,
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):
self.capath = '/etc/grid-security/certificates'
def _handleException(self, url, e):
f = open('/tmp/request-error.html', 'w')
print >>f,
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,
request = urllib2.Request(url, headers=headers, data=body)
request.get_method = lambda: method
response =
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):
def _ioctl(self, cmd):
if cmd == pycurl.IOCMD_RESTARTREAD:
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)
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)
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