Changeset 1881


Ignore:
Timestamp:
16/12/06 13:09:10 (13 years ago)
Author:
pjkersha
Message:

server/MyProxy.py:

  • added _HostCheck class - derived from M2Crypto.SSL.Checker.Checker. It

enables check of host identity but adapted to enable check of host
Distinguished Name against MYPROXY_SERVER_DN environment variable if set.

  • Moved generic connection code into _initConnection method.

conf/myProxyProperties.xml / test/MyProxy/myProxyProperties.xml: added
serverDN element - equivalent to MYPROXY_SERVER_DN environment variable setting.
test/MyProxy/myProxyClientTest.cfg / MyProxy/MyProxyClientTest?.py: various
fixes to tests.

Location:
TI12-security/trunk/python
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/conf/myProxyProperties.xml

    r1858 r1881  
    22<myProxyProp> 
    33        <!--  
    4         Nb. MYPROXY_SERVER environment variable if set, overrides this setting 
     4        Delete this element and take setting from MYPROXY_SERVER environment  
     5        variable ifrequired 
    56        --> 
    67        <hostname>localhost</hostname> 
     8        <!--  
     9        Delete this element to take default setting 7512 or read  
     10        MYPROXY_SERVER_PORT setting 
     11        --> 
    712        <port>7512</port> 
     13        <!-- 
     14        Useful if hostname and certificate CN don't match correctly.  Globus host 
     15        DN is set to "host/<fqdn>".  Delete this element and set from  
     16        MYPROXY_SERVER_DN environment variable if prefered 
     17        --> 
     18        <serverDN></serverDN> 
    819        <!-- 
    920        Nb. GRID_SECURITY_DIR environment variable if set, overrides this setting 
     
    2536                --> 
    2637        <proxyCertLifetime></proxyCertLifetime> <!-- in hours --> 
     38        <caCertFile></caCertFile> 
    2739</myProxyProp> 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/MyProxy.py

    r1861 r1881  
    2222import os 
    2323import socket 
    24 from M2Crypto import X509, RSA, EVP, m2, BIO 
    25 from M2Crypto.SSL.Context import Context 
    26 from M2Crypto.SSL.Connection import Connection 
     24from M2Crypto import X509, RSA, EVP, m2, BIO, SSL 
    2725 
    2826import re 
     
    4442    """Error recovering a response from MyProxy""" 
    4543 
    46  
     44class _HostCheck(SSL.Checker.Checker): 
     45    """Override SSL.Checker.Checker to allow additional check of MyProxy  
     46    server identity.  If hostname doesn't match, allow match of host's   
     47    Distinguished Name against MYPROXY_SERVER_DN setting""" 
     48 
     49    def __init__(self,  
     50                 myProxyServerDN=os.environ.get('MYPROXY_SERVER_DN'),  
     51                 **kw): 
     52        """Override parent class __init__ to enable setting of myProxyServerDN 
     53        setting 
     54         
     55        @param myProxyServerDN: Set the expected Distinguished Name of the 
     56        MyProxy server to avoid errors matching hostnames.  This is useful 
     57        where the hostname is not fully qualified""" 
     58        SSL.Checker.Checker.__init__(self, **kw) 
     59        self.myProxyServerDN = myProxyServerDN 
     60         
     61         
     62    def __call__(self, peerCert, host=None): 
     63        """Carry out checks on server ID 
     64        @param peerCert: MyProxy server host certificate as M2Crypto.X509.X509 
     65        instance 
     66        @param **kw: forward keywords to parent class method 
     67        """ 
     68         
     69        # Globus host certificate has a "host/" prefix 
     70        host = 'host/' + self.host 
     71         
     72        try: 
     73            SSL.Checker.Checker.__call__(self, peerCert, host=host) 
     74             
     75        except SSL.Checker.WrongHost, e: 
     76            # Try match against DN set from MYPROXY_SERVER_DN / config 
     77            # file setting 
     78            peerCertDN = '/' + \ 
     79                    peerCert.get_subject().as_text().replace(', ', '/') 
     80            if peerCertDN == self.myProxyServerDN: 
     81                # They match - drop the exception and return all OK instead 
     82                return True 
     83            else: 
     84                raise e 
     85             
     86         
    4787class MyProxyClient(object): 
    4888    """MyProxy client interface  
     
    61101    @cvar _certReqDNparamName: names of parameters needed to generate a  
    62102    certificate request e.g. CN, OU etc. 
     103    @cvar __validKeys: sets permissable element names for MyProxy XML config 
     104    file 
    63105    """ 
    64106       
     
    102144    __validKeys = ('hostname', 
    103145                   'port', 
     146                   'serverDN', 
    104147                   'gridSecurityDir', 
    105148                   'openSSLConfFileName', 
    106149                   'tmpDir', 
    107150                   'proxyCertMaxLifetime', 
    108                    'proxyCertLifetime') 
    109  
    110     # For checking whether MyProxy server name is localhost 
    111     __localHostname = socket.gethostname() 
    112     __localHostnames = (__localHostname, 
    113                         __localHostname.split('.')[0], 
    114                         "localhost",  
    115                         "127.0.0.1") 
     151                   'proxyCertLifetime', 
     152                   'caCertFile') 
    116153 
    117154    #_________________________________________________________________________             
     
    236273             
    237274        self.setProperties(**prop) 
    238      
    239  
    240     #_________________________________________________________________________         
    241     def __myProxyServerAtLocalHost(self): 
    242         """Check setting for MyProxy server address - if it's not the  
    243         local machine myproxy-admin-* commands won't work.  This affects 
    244         addUser and userIsRegistered commands"""         
    245         return self.__prop['hostname'] in self.__class__.__localHostnames 
     275 
    246276 
    247277    #_________________________________________________________________________         
     
    271301                            fget=__getCertReqDNparam, 
    272302                            doc="Dictionary of parameters for cert. request") 
    273      
     303             
     304    #_________________________________________________________________________         
     305    def _initConnection(self,  
     306                        ownerCertFile=None,  
     307                        ownerKeyFile=None, 
     308                        ownerPassphrase=None): 
     309        """Initialise connection setting up SSL context and client and 
     310        server side identity checks 
     311         
     312        @param ownerCertFile: client certificate and owner of credential 
     313        to be acted on.  Can be a proxy cert + proxy's signing cert.  Cert 
     314        and private key are not necessary for getDelegation / logon calls 
     315        @param ownerKeyFile: client private key file 
     316        @param ownerPassphrase: pass-phrase protecting private key if set -  
     317        not needed in the case of a proxy private key 
     318        """ 
     319 
     320        # Must be version 3 for MyProxy 
     321        context = SSL.Context(protocol='sslv3') 
     322        context.load_verify_locations(cafile=self.__prop['caCertFile']) 
     323         
     324        if ownerCertFile and ownerKeyFile: 
     325            context.load_cert_chain(ownerCertFile, 
     326                                keyfile=ownerKeyFile, 
     327                                callback=lambda *ar, **kw: ownerPassphrase) 
     328                 
     329            # Stop if peer's certificate can't be verified 
     330            context.set_allow_unknown_ca(False) 
     331             
     332            # Verify peer's certificate 
     333            context.set_verify(SSL.verify_peer, 1)  
     334         
     335            
     336        # Disable for compatibility with myproxy server (er, globus) 
     337        # globus doesn't handle this case, apparently, and instead 
     338        # chokes in proxy delegation code 
     339        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
     340         
     341        # connect to myproxy server 
     342        conn = SSL.Connection(context, sock=socket.socket()) 
     343         
     344        # Check server host identity - if host doesn't match use explicit 
     345        # 'serverDN'  
     346        # host/<hostname> one 
     347        hostCheck = _HostCheck(host=self.__prop['hostname'], 
     348                               myProxyServerDN=self.__prop.get('serverDN')) 
     349        conn.set_post_connection_check_callback(hostCheck) 
     350         
     351        return conn 
     352     
     353             
    274354    #_________________________________________________________________________         
    275355    def _createCertReq(self, CN, nBitsForKey=1024, messageDigest="md5"): 
     
    437517            "No client authentication cert. and private key file were given" 
    438518 
    439         context = Context(protocol='sslv3') 
    440         context.load_cert(ownerCertFile, 
    441                           keyfile=ownerKeyFile, 
    442                           callback=lambda *ar, **kw: ownerPassphrase) 
    443      
    444         # Disable for compatibility with myproxy server (er, globus) 
    445         # globus doesn't handle this case, apparently, and instead 
    446         # chokes in proxy delegation code 
    447         context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
    448          
    449         # connect to myproxy server 
    450         conn = Connection(context, sock=socket.socket()) 
    451          
    452         # Fudge to avoid checking client cert - seems to pick globus  
    453         # host/<hostname> one 
    454         conn.clientPostConnectionCheck = None 
     519        # Set-up SSL connection 
     520        conn = self._initConnection(ownerCertFile=ownerCertFile, 
     521                                    ownerKeyFile=ownerKeyFile, 
     522                                    ownerPassphrase=ownerPassphrase) 
     523         
    455524        conn.connect((self.__prop['hostname'], self.__prop['port'])) 
    456525         
     
    511580            "No client authentication cert. and private key file were given" 
    512581         
    513         context = Context(protocol='sslv3') 
    514         context.load_cert(ownerCertFile, 
    515                           keyfile=ownerKeyFile, 
    516                           callback=lambda *ar, **kw: ownerPassphrase) 
    517      
    518         # Disable for compatibility with myproxy server (er, globus) 
    519         # globus doesn't handle this case, apparently, and instead 
    520         # chokes in proxy delegation code 
    521         context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
    522          
    523         # connect to myproxy server 
    524         conn = Connection(context, sock=socket.socket()) 
    525          
    526         # Fudge to avoid checking client cert - seems to pick globus  
    527         # host/<hostname> one 
    528         conn.clientPostConnectionCheck = None 
     582        # Set-up SSL connection 
     583        conn = self._initConnection(ownerCertFile=ownerCertFile, 
     584                                    ownerKeyFile=ownerKeyFile, 
     585                                    ownerPassphrase=ownerPassphrase) 
     586 
    529587        conn.connect((self.__prop['hostname'], self.__prop['port'])) 
    530588         
     
    579637            "No client authentication cert. and private key file were given" 
    580638         
    581  
    582         context = Context(protocol='sslv3') 
    583         context.load_cert(ownerCertFile, 
    584                           keyfile=ownerKeyFile, 
    585                           callback=lambda *ar, **kw: ownerPassphrase) 
    586      
    587         # Disable for compatibility with myproxy server (er, globus) 
    588         # globus doesn't handle this case, apparently, and instead 
    589         # chokes in proxy delegation code 
    590         context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
    591          
    592         # connect to myproxy server 
    593         conn = Connection(context, sock=socket.socket()) 
    594          
    595         # Fudge to avoid checking client cert - seems to pick globus  
    596         # host/<hostname> one 
    597         conn.clientPostConnectionCheck = None 
     639        # Set-up SSL connection 
     640        conn = self._initConnection(ownerCertFile=ownerCertFile, 
     641                                    ownerKeyFile=ownerKeyFile, 
     642                                    ownerPassphrase=ownerPassphrase) 
     643 
    598644        conn.connect((self.__prop['hostname'], self.__prop['port'])) 
    599645         
     
    672718 
    673719        # Set up SSL connection 
    674         context = Context(protocol='sslv3') 
    675         context.load_cert(ownerCertFile, 
    676                           keyfile=ownerKeyFile, 
    677                           callback=lambda *ar, **kw: ownerPassphrase) 
    678      
    679         # Disable for compatibility with myproxy server (er, globus) 
    680         # globus doesn't handle this case, apparently, and instead 
    681         # chokes in proxy delegation code 
    682         context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
    683          
    684         # connect to myproxy server 
    685         conn = Connection(context, sock=socket.socket()) 
    686          
    687         # Fudge to avoid checking client cert - seems to pick globus  
    688         # host/<hostname> one 
    689         conn.clientPostConnectionCheck = None 
     720        conn = self._initConnection(ownerCertFile=ownerCertFile, 
     721                                    ownerKeyFile=ownerKeyFile, 
     722                                    ownerPassphrase=ownerPassphrase) 
     723         
    690724        conn.connect((self.__prop['hostname'], self.__prop['port'])) 
    691725         
     
    739773        certReq, priKey = self._createCertReq(username) 
    740774 
    741  
    742         context = Context(protocol='sslv3') 
    743          
    744         # disable for compatibility with myproxy server (er, globus) 
    745         # globus doesn't handle this case, apparently, and instead 
    746         # chokes in proxy delegation code 
    747         context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
    748          
    749         # connect to myproxy server 
    750         conn = Connection(context, sock=socket.socket()) 
    751          
    752         # Fudge to avoid checking client cert - seems to pick globus  
    753         # host/<hostname> one 
    754         conn.clientPostConnectionCheck = None 
     775        # Set-up SSL connection 
     776        conn = self._initConnection() 
    755777        conn.connect((self.__prop['hostname'], self.__prop['port'])) 
    756778         
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/MyProxy/MyProxyClientTest.py

    r1861 r1881  
    6565            print "proxy credentials:"  
    6666            print ''.join(creds) 
     67            open('proxy-cert.pem', 'w').write(creds[0]+''.join(creds[2:])) 
     68            open('proxy-key.pem', 'w').write(creds[1]) 
    6769        except: 
    6870            self.fail(traceback.print_exc()) 
     
    7173    def test3Info(self): 
    7274        '''test3Info: Retrieve information about a given credential''' 
     75        ownerpassphrase = self.cfg['test3Info']['ownerpassphrase'] or \ 
     76            getpass.getpass(prompt="\ntest3Info owner creds pass-phrase: ") 
     77 
     78        ownerpassphrase = (ownerpassphrase == 'None') and None 
     79         
    7380        try: 
    74             credExists, errorTxt, fields = clnt.info( 
     81            credExists, errorTxt, fields = self.clnt.info( 
    7582                                 self.cfg['test3Info']['username'], 
    7683                                 self.cfg['test3Info']['ownercertfile'], 
     
    7885                                 ownerPassphrase=ownerpassphrase) 
    7986            print "test3Info... " 
    80             print "credExists: " + credExists 
     87            print "credExists: %s" % credExists 
    8188            print "errorTxt: " + errorTxt 
    82             print "fields: " + fields 
     89            print "fields: %s" % fields 
    8390        except: 
    8491            self.fail(traceback.print_exc()) 
     
    8895        """test4ChangePassphrase: change pass-phrase protecting a given 
    8996        credential""" 
     97        passphrase = \ 
     98            self.cfg['test4ChangePassphrase']['ownerpassphrase'] or \ 
     99            getpass.getpass(prompt="\test4ChangePassphrase - pass-phrase: ") 
     100             
     101        newPassphrase = \ 
     102        self.cfg['test4ChangePassphrase']['ownerpassphrase'] or \ 
     103        getpass.getpass(prompt="\test4ChangePassphrase - new pass-phrase: ") 
     104 
     105        confirmNewPassphrase = \ 
     106        self.cfg['test4ChangePassphrase']['ownerpassphrase'] or \ 
     107            getpass.getpass(\ 
     108                prompt="\test4ChangePassphrase - confirm new pass-phrase: ") 
     109 
     110        ownerPassphrase = (ownerPassphrase == 'None') and passphrase 
    90111     
    91112        try: 
     
    96117                         self.cfg['test4ChangePassphrase']['ownercertfile'], 
    97118                         self.cfg['test4ChangePassphrase']['ownerkeyfile'], 
    98                          ownerPassphrase=ownerpassphrase) 
     119                         ownerPassphrase=ownerPassphrase) 
    99120            print "Change pass-phrase" 
    100121        except: 
     
    108129            getpass.getpass(prompt="\ntest5Destroy cred. owner pass-phrase: ") 
    109130 
     131        ownerPassphrase = (ownerPassphrase == 'None') and None 
     132 
    110133        try: 
    111134            self.clnt.destroy(self.cfg['test5Destroy']['username'],  
    112135                    ownerCertFile=self.cfg['test5Destroy']['ownercertfile'], 
    113136                    ownerKeyFile=self.cfg['test5Destroy']['ownerkeyfile'], 
    114                     ownerPassphrase=ownerpassphrase) 
    115             print "Destroy creds for user %s" % username 
     137                    ownerPassphrase=ownerPassphrase) 
     138            print "Destroy creds for user %s" % \ 
     139                                        self.cfg['test5Destroy']['username'] 
    116140        except: 
    117141            self.fail(traceback.print_exc()) 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/MyProxy/myProxyClientTest.cfg

    r1861 r1881  
    2424[test3Info] 
    2525username: sstljakTestUser 
    26 ownerCertFile: 
    27 ownerKeyFile: 
    28 ownerPassphrase: 
     26ownerCertFile: ./proxy-cert.pem 
     27ownerKeyFile: ./proxy-key.pem 
     28ownerPassphrase: None 
    2929 
    3030[test4ChangePassphrase] 
    3131username: sstljakTestUser 
    32 ownerCertFile: 
    33 ownerKeyFile: 
    34 ownerPassphrase: 
     32ownerCertFile: ./proxy-cert.pem 
     33ownerKeyFile: ./proxy-key.pem 
     34passphrase:  
     35newPassphrase: 
     36ownerPassphrase: None 
    3537 
    3638[test5Destroy] 
    3739username: sstljakTestUser 
    38 ownerCertFile: 
    39 ownerKeyFile: 
    40 ownerPassphrase: 
     40ownerCertFile: ./proxy-cert.pem 
     41ownerKeyFile: ./proxy-key.pem 
     42ownerPassphrase: None 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/MyProxy/myProxyProperties.xml

    r1858 r1881  
    22<myProxyProp> 
    33        <!--  
    4         Nb. MYPROXY_SERVER environment variable if set, overrides this setting 
     4        Delete this element and take setting from MYPROXY_SERVER environment  
     5        variable ifrequired 
    56        --> 
    67        <hostname>localhost</hostname> 
     8        <!--  
     9        Delete this element to take default setting 7512 or read  
     10        MYPROXY_SERVER_PORT setting 
     11        --> 
    712        <port>7512</port> 
     13        <!-- 
     14        Useful if hostname and certificate CN don't match correctly.  Globus host 
     15        DN is set to "host/<fqdn>".  Delete this element and set from  
     16        MYPROXY_SERVER_DN environment variable if prefered 
     17        --> 
     18        <serverDN>/O=NDG/OU=sstljak/CN=host/sstljak</serverDN> 
    819        <!-- 
    920        Nb. GRID_SECURITY_DIR environment variable if set, overrides this setting 
     
    2940        <proxyCertLifetime></proxyCertLifetime> 
    3041        --> 
     42        <caCertFile>cacert.pem</caCertFile> 
    3143</myProxyProp> 
Note: See TracChangeset for help on using the changeset viewer.