Package myproxy :: Package ws :: Package client
[hide private]

Source Code for Package myproxy.ws.client

  1  """MyProxy Web Service - web services client package 
  2   
  3  """ 
  4  __author__ = "P J Kershaw" 
  5  __date__ = "28/05/12" 
  6  __copyright__ = "(C) 2012 Science and Technology Facilities Council" 
  7  __license__ = "BSD - see LICENSE file in top-level directory" 
  8  __contact__ = "Philip.Kershaw@stfc.ac.uk" 
  9  __revision__ = '$Id$' 
 10  import logging 
 11  log = logging.getLogger(__name__) 
 12  import base64 
 13  import os 
 14  import errno 
 15  import urllib2 
 16  from urlparse import urlparse, urlunparse 
 17   
 18  from OpenSSL import SSL, crypto 
 19  from ndg.httpsclient.utils import (_should_use_proxy, fetch_stream_from_url,  
 20                                     Configuration) 
 21  from ndg.httpsclient.ssl_context_util import make_ssl_context 
 22  from ndg.httpsclient.urllib2_build_opener import build_opener 
 23   
 24  testvar = True 
25 26 -class MyProxyWSClient(object):
27 PRIKEY_NBITS = 2048 28 MESSAGE_DIGEST_TYPE = "md5" 29 CERT_REQ_POST_PARAM_KEYNAME = 'certificate_request' 30 TRUSTED_CERTS_FIELDNAME = 'TRUSTED_CERTS' 31 TRUSTED_CERTS_FILEDATA_FIELDNAME_PREFIX = 'FILEDATA_' 32
33 - def __init__(self):
34 self.__ca_cert_dir = None 35 self.timeout = 500
36 37 @property
38 - def ca_cert_dir(self):
39 return self.__ca_cert_dir
40 41 @ca_cert_dir.setter
42 - def ca_cert_dir(self, val):
43 if not isinstance(val, basestring): 44 raise TypeError('Expecting string type for "ca_cert_dir"; got %r' % 45 type(val)) 46 47 self.__ca_cert_dir = val
48 49 @staticmethod
50 - def create_key_pair(n_bits_for_key=PRIKEY_NBITS):
51 """Generate key pair and return as PEM encoded string 52 @type n_bits_for_key: int 53 @param n_bits_for_key: number of bits for private key generation - 54 default is 2048 55 @rtype: OpenSSL.crypto.PKey 56 @return: public/private key pair 57 """ 58 key_pair = crypto.PKey() 59 key_pair.generate_key(crypto.TYPE_RSA, n_bits_for_key) 60 61 return key_pair
62 63 @staticmethod
64 - def create_cert_req(key_pair, message_digest=MESSAGE_DIGEST_TYPE):
65 """Create a certificate request. 66 67 @type CN: basestring 68 @param CN: Common Name for certificate - effectively the same as the 69 username for the MyProxy credential 70 @type keyPair: string/None 71 @param keyPair: public/private key pair 72 @type messageDigest: basestring 73 @param messageDigest: message digest type - default is MD5 74 @rtype: base string 75 @return certificate request PEM text and private key PEM text 76 """ 77 78 # Check all required certifcate request DN parameters are set 79 # Create certificate request 80 cert_req = crypto.X509Req() 81 82 # Create public key object 83 cert_req.set_pubkey(key_pair) 84 85 # Add the public key to the request 86 cert_req.sign(key_pair, message_digest) 87 88 cert_req = crypto.dump_certificate_request(crypto.FILETYPE_PEM, 89 cert_req) 90 91 return cert_req
92
93 - def logon(self, username, password, server_url, proxies=None, no_proxy=None, 94 cert_life_time=86400, ssl_ctx=None):
95 """Obtain a new certificate""" 96 if ssl_ctx is None: 97 ssl_ctx = make_ssl_context(ca_dir=self.ca_cert_dir, verify_peer=True, 98 url=server_url, 99 method=SSL.SSLv3_METHOD) 100 101 # Create a password manager 102 password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 103 104 # Get base URL for setting basic auth scope 105 parsed_url = urlparse(server_url) 106 base_url = urlunparse(parsed_url[0:2] + ('/', '', '', '')) 107 108 # Add the username and password. 109 # If we knew the realm, we could use it instead of ``None``. 110 password_mgr.add_password(None, base_url, username, password) 111 112 handlers = [urllib2.HTTPBasicAuthHandler(password_mgr)] 113 114 key_pair = self.__class__.create_key_pair() 115 cert_req = self.__class__.create_cert_req(key_pair) 116 117 # Convert plus chars to make it safe for HTTP POST 118 encoded_cert_req = cert_req.replace('+', '%2B') 119 req = "%s=%s\n" % (self.__class__.CERT_REQ_POST_PARAM_KEYNAME, 120 encoded_cert_req) 121 config = Configuration(ssl_ctx, True) 122 res = fetch_stream_from_url(server_url, config, data=req, 123 handlers=handlers) 124 125 return res
126
127 - def get_trustroots(self, server_url, write_to_ca_cert_dir=False, 128 bootstrap=False):
129 """Get trustroots""" 130 raise NotImplementedError('To be completed in a subsequent release') 131 prefix = self.__class__.TRUSTED_CERTS_FILEDATA_FIELDNAME_PREFIX 132 field_name = self.__class__.TRUSTED_CERTS_FIELDNAME 133 file_data = {} 134 135 files_dict = dict([(k.split(prefix, 1)[1], base64.b64decode(v)) 136 for k, v in file_data.items() if k != field_name]) 137 138 if write_to_ca_cert_dir: 139 # Create the CA directory path if doesn't already exist 140 try: 141 os.makedirs(self.ca_cert_dir) 142 except OSError, e: 143 # Ignore if the path already exists 144 if e.errno != errno.EEXIST: 145 raise 146 147 for file_name, file_contents in files_dict.items(): 148 file_path = os.path.join(self.ca_cert_dir, file_name) 149 open(file_path, 'wb').write(file_contents) 150 151 return files_dict
152