Changeset 8102


Ignore:
Timestamp:
22/08/12 16:55:12 (8 years ago)
Author:
pjkersha
Message:
  • working Python client logon method
  • fix to HTTP Basic Auth middleware - fixed header syntax for server response
Location:
trunk/MyProxyWebService/myproxy/ws
Files:
3 added
4 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/MyProxyWebService/myproxy/ws/client/__init__.py

    r8072 r8102  
    33""" 
    44__author__ = "P J Kershaw" 
    5 __date__ = "09/12/10" 
    6 __copyright__ = "(C) 2010 Science and Technology Facilities Council" 
     5__date__ = "28/05/12" 
     6__copyright__ = "(C) 2012 Science and Technology Facilities Council" 
    77__license__ = "BSD - see LICENSE file in top-level directory" 
    88__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    99__revision__ = '$Id$' 
     10import logging 
     11log = logging.getLogger(__name__) 
    1012import base64 
    1113import os 
    1214import errno 
    1315import urllib2 
     16from urlparse import urlparse, urlunparse 
    1417 
    1518from OpenSSL import SSL, crypto 
     19from ndg.httpsclient.utils import (_should_use_proxy, fetch_stream_from_url,  
     20                                   Configuration) 
     21from ndg.httpsclient.ssl_context_util import make_ssl_context 
    1622from ndg.httpsclient.urllib2_build_opener import build_opener 
    1723 
     
    1925 
    2026class MyProxyWSClient(object): 
    21     PRIKEY_NBITS = 4096 
     27    PRIKEY_NBITS = 2048 
    2228    MESSAGE_DIGEST_TYPE = "md5" 
    2329    CERT_REQ_POST_PARAM_KEYNAME = 'certificate_request' 
     
    8288        cert_req = crypto.dump_certificate_request(crypto.FILETYPE_PEM,  
    8389                                                   cert_req) 
    84  
     90         
    8591        return cert_req 
    8692         
    87     def logon(self, username, password, myproxy_server_url,  
     93    def logon(self, username, password, server_url, proxies=None, no_proxy=None, 
    8894              cert_life_time=86400): 
    8995        """Obtain a new certificate""" 
    90         ctx = SSL.Context(SSL.SSLv3_METHOD) 
    91         verify_callback = lambda conn, x509, errnum, errdepth, preverify_ok: \ 
    92             preverify_ok  
    93              
    94         ctx.set_verify(SSL.VERIFY_PEER, verify_callback) 
    95         ctx.load_verify_locations(None, self.ca_cert_dir) 
     96        ctx = make_ssl_context(ca_dir=self.ca_cert_dir, verify_peer=True,  
     97                               url=server_url,  
     98                               method=SSL.SSLv3_METHOD) 
    9699         
    97         # create a password manager 
     100        # Create a password manager 
    98101        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 
     102         
     103        # Get base URL for setting basic auth scope 
     104        parsed_url = urlparse(server_url) 
     105        base_url = urlunparse(parsed_url[0:2] + ('/', '', '', '')) 
    99106         
    100107        # Add the username and password. 
    101108        # If we knew the realm, we could use it instead of ``None``. 
    102         password_mgr.add_password(None, myproxy_server_url, username, password) 
     109        password_mgr.add_password(None, base_url, username, password) 
    103110         
    104         basicauth_handler = urllib2.HTTPBasicAuthHandler(password_mgr) 
    105          
    106         opener = build_opener(basicauth_handler, ssl_context=ctx) 
    107          
     111        handlers = [urllib2.HTTPBasicAuthHandler(password_mgr)] 
     112             
    108113        key_pair = self.__class__.create_key_pair() 
    109114        cert_req = self.__class__.create_cert_req(key_pair) 
    110115         
    111         req = "%s=%s\n" % (self.__class__.CERT_REQ_POST_PARAM_KEYNAME, cert_req) 
    112         res = opener.open(myproxy_server_url, req, self.timeout) 
     116        # Convert plus chars to make it safe for HTTP POST 
     117        encoded_cert_req = cert_req.replace('+', '%2B') 
     118        req = "%s=%s\n" % (self.__class__.CERT_REQ_POST_PARAM_KEYNAME,  
     119                           encoded_cert_req) 
     120        config = Configuration(ctx, True) 
     121        res = fetch_stream_from_url(server_url, config, data=req,  
     122                                    handlers=handlers) 
    113123         
    114124        return res 
    115125         
    116     def get_trustroots(self, write_to_ca_cert_dir=False, bootstrap=False): 
     126    def get_trustroots(self, server_url, write_to_ca_cert_dir=False,  
     127                       bootstrap=False): 
    117128        """Get trustroots""" 
     129        raise NotImplementedError('To be completed in a subsequent release') 
    118130        prefix = self.__class__.TRUSTED_CERTS_FILEDATA_FIELDNAME_PREFIX 
    119131        field_name = self.__class__.TRUSTED_CERTS_FIELDNAME 
  • trunk/MyProxyWebService/myproxy/ws/client/test/test_client.py

    r8082 r8102  
    1 ''' 
    2 Created on May 28, 2012 
     1#!/usr/bin/env python 
     2"""Unit tests for MyProxy Web Service client  
     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$' 
     10import logging 
     11logging.basicConfig(level=logging.DEBUG) 
     12import unittest 
     13import os 
     14from getpass import getpass 
     15from ConfigParser import SafeConfigParser, NoOptionError 
    316 
    4 @author: philipkershaw 
    5 ''' 
    6 import unittest 
     17from OpenSSL import crypto 
    718 
    819from myproxy.ws.client import MyProxyWSClient 
    920from myproxy.ws.test import test_ca_dir 
    1021 
     22 
    1123class WSClientTestCase(unittest.TestCase): 
    1224    """Test MyProxy Web Service Client""" 
     25    here_dir = os.path.dirname(os.path.abspath(__file__)) 
     26    config_filepath = os.path.join(here_dir,  
     27                                   'test_myproxywebservice_client.cfg') 
    1328     
    14     def test_logon(self): 
     29    def __init__(self, *args, **kwargs): 
     30        self.cfg = SafeConfigParser({'here': self.__class__.here_dir}) 
     31        self.cfg.optionxform = str 
     32        self.cfg.read(self.__class__.config_filepath) 
     33         
     34        unittest.TestCase.__init__(self, *args, **kwargs)   
     35           
     36    def test01_logon(self): 
     37        opt_name = 'WSClientTestCase.test01_logon' 
     38        username = self.cfg.get(opt_name, 'username') 
     39        try:  
     40            password = self.cfg.get(opt_name, 'password') 
     41        except NoOptionError: 
     42            password = getpass('WSClientTestCase.test01_logon password: ') 
     43 
     44        server_url = self.cfg.get(opt_name, 'uri') 
     45         
    1546        myproxy_client = MyProxyWSClient() 
    1647        myproxy_client.ca_cert_dir = test_ca_dir 
    1748         
    18         myproxy_server_url = 'https://localhost/logon' 
    19         username = 'testuser' 
    20         password = '' 
    21         res = myproxy_client.logon(username, password, myproxy_server_url) 
     49        res = myproxy_client.logon(username, password, server_url) 
    2250        self.assert_(res) 
     51         
     52        pem_out = res.read() 
     53        cert = crypto.load_certificate(crypto.FILETYPE_PEM, pem_out) 
     54        subj = cert.get_subject() 
     55        self.assert_(subj) 
     56        self.assert_(subj.CN) 
     57        print("Returned certificate subject CN=%r" % subj) 
     58 
     59if __name__ == "__main__": 
     60    unittest.main()  
  • trunk/MyProxyWebService/myproxy/ws/server/wsgi/httpbasicauth.py

    r6997 r8102  
    7070    content 
    7171    @type AUTHZ_ENV_KEYNAME: string 
     72    @cvar AUTHN_HDR_FORMAT: HTTP Basic Auth format string following RFC2617 
     73    @type AUTHN_HDR_FORMAT: string 
    7274     
    7375    @ivar __rePathMatchList: list of regular expression patterns used to match 
     
    102104    FIELD_SEP = ':' 
    103105    AUTHZ_ENV_KEYNAME = 'HTTP_AUTHORIZATION' 
     106     
     107    AUTHN_HDR_FORMAT = '%s ' + REALM_OPTNAME + '="%s"'  
    104108     
    105109    __slots__ = ( 
     
    319323                      
    320324                if not authnRealmHdrFound: 
     325                    # Nb. realm requires double quotes according to RFC 
    321326                    authnRealmHdr = (self.__class__.AUTHENTICATE_HDR_FIELDNAME, 
    322                                      "%s %s" % (                                    
     327                                     self.__class__.AUTHN_HDR_FORMAT % (                                    
    323328                                     self.__class__.AUTHN_SCHEME_HDR_FIELDNAME, 
    324329                                     self.realm)) 
  • trunk/MyProxyWebService/myproxy/ws/server/wsgi/middleware.py

    r8101 r8102  
    176176                                                     httplib.METHOD_NOT_ALLOWED) 
    177177                 
    178             certReqKey = self.__class__.CERT_REQ_POST_PARAM_KEYNAME 
    179             pemCertReq = request.POST.get(certReqKey) 
    180             if pemCertReq is None: 
     178            # Extract cert request and convert to standard string - SSL library 
     179            # will not accept unicode 
     180            cert_req_key = self.__class__.CERT_REQ_POST_PARAM_KEYNAME 
     181            pem_cert_req = str(request.POST.get(cert_req_key)) 
     182            if pem_cert_req is None: 
    181183                response = ("No %r form variable set in POST message" %  
    182                             certReqKey) 
     184                            cert_req_key) 
    183185                log.error(response) 
    184186                raise HttpBasicAuthResponseException(response,  
    185187                                                     httplib.BAD_REQUEST) 
    186188         
    187             log.debug("cert req = %r", pemCertReq) 
     189            log.debug("cert req = %r", pem_cert_req) 
    188190             
    189191            # Expecting PEM encoded request 
    190192            try: 
    191                 certReq = crypto.load_certificate_request( 
    192                                                         crypto.FILETYPE_PEM, 
    193                                                         pemCertReq) 
     193                cert_req = crypto.load_certificate_request(crypto.FILETYPE_PEM, 
     194                                                           pem_cert_req) 
    194195            except crypto.Error, e: 
    195196                log.error("Error loading input certificate request: %r",  
    196                           pemCertReq) 
     197                          pem_cert_req) 
    197198                raise HttpBasicAuthResponseException("Error loading input " 
    198199                                                     "certificate request", 
     
    200201             
    201202            # Convert to ASN1 format expect by logon client call 
    202             asn1CertReq = crypto.dump_certificate_request( 
    203                                                     crypto.FILETYPE_ASN1,  
    204                                                     certReq) 
     203            asn1CertReq = crypto.dump_certificate_request(crypto.FILETYPE_ASN1,  
     204                                                          cert_req) 
    205205 
    206206            try: 
  • trunk/MyProxyWebService/myproxy/ws/test/myproxy_ws.py

    r8094 r8102  
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = "$Id: $" 
     11import logging 
     12logging.basicConfig(level=logging.DEBUG) 
    1113from os import path 
    1214 
Note: See TracChangeset for help on using the changeset viewer.