Ignore:
Timestamp:
02/06/10 15:01:16 (11 years ago)
Author:
pjkersha
Message:

Incomplete - task 5: MyProxy? Logon HTTPS Interface

  • Updated MyProxyClient with bootstrap capability for get trust roots and logon methods.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/MyProxyClient/myproxy/client.py

    r6847 r6918  
    243243    environment variable name 
    244244     
     245    @type GLOBUS_LOCATION_ENVVARNAME: string 
     246    @param GLOBUS_LOCATION_ENVVARNAME: 'GLOBUS_LOCATION' environment variable 
     247    name 
     248     
    245249    @type GET_CMD: string 
    246250    @cvar GET_CMD: get command string 
     
    261265    @cvar GET_TRUST_ROOTS_CMD: get trust roots command string 
    262266     
    263     @type _hostCertSubDirPath: string 
    264     @cvar _hostCertSubDirPath: sub-directory path host certificate (as tuple) 
    265      
    266     @type _hostKeySubDirPath: string 
    267     @cvar _hostKeySubDirPath: sub-directory path to host key (as tuple) 
     267    @type TRUSTED_CERTS_FIELDNAME: string 
     268    @param TRUSTED_CERTS_FIELDNAME: field name in get trust roots response for 
     269    trusted certificate file names 
     270     
     271    @type TRUSTED_CERTS_FILEDATA_FIELDNAME_PREFIX: string 
     272    @param TRUSTED_CERTS_FILEDATA_FIELDNAME_PREFIX: field name prefix in get  
     273    trust roots response for trusted certificate file contents 
     274     
     275    @type HOSTCERT_SUBDIRPATH: string 
     276    @cvar HOSTCERT_SUBDIRPATH: sub-directory path host certificate (as tuple) 
     277     
     278    @type HOSTKEY_SUBDIRPATH: string 
     279    @cvar HOSTKEY_SUBDIRPATH: sub-directory path to host key (as tuple) 
    268280     
    269281    @type PRIKEY_NBITS: int 
     
    290302    @cvar PROPERTY_DEFAULTS: sets permissable element names for MyProxy config  
    291303    file 
     304 
     305    @type ROOT_USERNAME: string 
     306    @cvar ROOT_USERNAME: root username - used to determine output directory 
     307    for trust roots 
     308 
     309    @type ROOT_TRUSTROOT_DIR: string 
     310    @param ROOT_TRUSTROOT_DIR: default trust root directory if running as root 
     311    user  
     312 
     313    @type USER_TRUSTROOT_DIR: string 
     314    @param USER_TRUSTROOT_DIR: default trust root directory for users other 
     315    than root 
     316     
     317    @type X509_CERT_DIR_ENVVARNAME: string 
     318    @param X509_CERT_DIR_ENVVARNAME: environment variable name 'X509_CERT_DIR', 
     319    which if set points to the location of the trust roots  
    292320    """ 
    293321    MYPROXY_SERVER_ENVVARNAME = 'MYPROXY_SERVER' 
    294322    MYPROXY_SERVER_PORT_ENVVARNAME = 'MYPROXY_SERVER_PORT' 
    295323    MYPROXY_SERVER_DN_ENVVARNAME = 'MYPROXY_SERVER_DN' 
    296        
     324     
     325    GLOBUS_LOCATION_ENVVARNAME = 'GLOBUS_LOCATION' 
     326     
    297327    GET_CMD="""VERSION=MYPROXYv2 
    298328COMMAND=0 
     
    339369TRUSTED_CERTS=1""" 
    340370 
    341     _hostCertSubDirPath = ('etc', 'hostcert.pem') 
    342     _hostKeySubDirPath = ('etc', 'hostkey.pem') 
     371    TRUSTED_CERTS_FIELDNAME = 'TRUSTED_CERTS' 
     372    TRUSTED_CERTS_FILEDATA_FIELDNAME_PREFIX = 'FILEDATA_' 
     373     
     374    HOSTCERT_SUBDIRPATH = ('etc', 'hostcert.pem') 
     375    HOSTKEY_SUBDIRPATH = ('etc', 'hostkey.pem') 
    343376     
    344377    PROXY_FILE_PERMISSIONS = 0600 
     
    360393       'hostname':              'localhost', 
    361394       'port':                  7512, 
     395       'cnPrefix':          MyProxyServerSSLCertVerification.SERVER_CN_PREFIX, 
    362396       'serverDN':              None, 
    363397       'openSSLConfFilePath':   '', 
    364398       'proxyCertMaxLifetime':  43200, 
    365399       'proxyCertLifetime':     43200, 
    366        'caCertFilePath':        None, 
    367400       'caCertDir':             None 
    368401    } 
     402 
     403    ROOT_USERNAME = 'root' 
     404    ROOT_TRUSTROOT_DIR = '/etc/grid-security/certificates' 
     405    USER_TRUSTROOT_DIR = '~/.globus/certificates'     
     406    X509_CERT_DIR_ENVVARNAME = 'X509_CERT_DIR' 
    369407     
    370408    # Restrict attributes to the above properties, their equivalent  
     
    395433        self.__proxyCertLifetime = MyProxyClient.PROPERTY_DEFAULTS[ 
    396434                                                        'proxyCertLifetime'] 
    397         self.__caCertFilePath = None 
    398435        self.__caCertDir = None 
    399436         
     
    419456            self.serverDN = serverDN 
    420457         
     458        # Set trust root - the directory containing the CA certificates for  
     459        # verifying the MyProxy server's SSL certificate 
     460        self.setDefaultCACertDir() 
     461         
    421462        # Any keyword settings override the defaults above 
    422463        for opt, val in prop.items(): 
     
    427468        if cfgFilePath is not None: 
    428469            self.parseConfig(cfg=cfgFilePath) 
    429  
    430     def _getServerSSLCertVerify(self): 
    431         return self.__serverSSLCertVerify 
    432  
    433     serverSSLCertVerify = property(_getServerSSLCertVerify,  
    434                                    doc="Server SSL Certificate Verification " 
    435                                        "callable") 
    436  
     470             
     471    def setDefaultCACertDir(self): 
     472        '''Make default trust root setting - the directory containing the CA  
     473        certificates for verifying the MyProxy server's SSL certificate. 
     474         
     475        The setting is made by using standard Globus defined locations and 
     476        environment variable settings 
     477        ''' 
     478         
     479        # Check for X509_CERT_DIR environment variable 
     480        x509CertDir = os.environ.get(MyProxyClient.X509_CERT_DIR_ENVVARNAME) 
     481        if x509CertDir is not None: 
     482            self.caCertDir = x509CertDir 
     483             
     484        # Check for running as root user 
     485        elif os.environ.get(MyProxyClient.ROOT_USERNAME) is not None: 
     486            self.caCertDir = MyProxyClient.ROOT_TRUSTROOT_DIR 
     487             
     488        # Default to non-root standard location 
     489        else: 
     490            self.caCertDir = os.path.expanduser( 
     491                                            MyProxyClient.USER_TRUSTROOT_DIR) 
    437492 
    438493    def _getServerSSLCertVerify(self): 
     
    582637                                 doc="Default proxy cert. lifetime used in " 
    583638                                     "logon request") 
    584      
    585     def _getCACertFilePath(self): 
    586         return self.__caCertFilePath 
    587      
    588     def _setCACertFilePath(self, val): 
    589         '''@type val: basestring 
    590         @param val: file path for CA certificate to be used to verify  
    591         MyProxy server certificate''' 
    592          
    593         if isinstance(val, basestring): 
    594             if val == '': 
    595                 self.__caCertFilePath = None 
    596             else: 
    597                 self.__caCertFilePath = os.path.expandvars(val) 
    598                  
    599         elif isinstance(val, None): 
    600             raise TypeError("Expecting string type for caCertFilePath " 
    601                                  "attribute")        
    602          
    603     caCertFilePath = property(fget=_getCACertFilePath, 
    604                               fset=_setCACertFilePath, 
    605                               doc="CA certificate file path - MyProxy server " 
    606                                   "certificate must validate against it and/" 
    607                                   "or any present in caCertDir") 
    608639 
    609640    def _getCACertDir(self): 
     
    634665    caCertDir = property(fget=_getCACertDir, 
    635666                         fset=_setCACertDir, 
    636                          doc="directory containing PEM encoded CA " 
    637                              "certificates.  Use along with caCertFilePath " 
    638                              "setting to validate MyProxy server certificate") 
     667                         doc="trust roots directory containing PEM encoded CA " 
     668                             "certificates to validate MyProxy server " 
     669                             "certificate") 
    639670 
    640671 
     
    648679                        certFile=None,  
    649680                        keyFile=None, 
    650                         keyFilePassphrase=None): 
     681                        keyFilePassphrase=None, 
     682                        verifyPeerWithTrustRoots=True): 
    651683        """Initialise connection setting up SSL context and client and 
    652684        server side identity checks 
     
    661693        @type keyFilePassphrase: basestring 
    662694        @param keyFilePassphrase: pass-phrase protecting private key if set 
     695        @type verifyPeerWithTrustRoots: bool 
     696        @param verifyPeerWithTrustRoots: verify MyProxy server's SSL certificate 
     697        against a list of trusted CA certificates in the CA certificate  
     698        directory set by the "CaCertDir" attribute.  This should always be set  
     699        to True for MyProxy client calls unless using the 'bootstrap' trust 
     700        roots mode available with logon and get trust roots calls 
    663701        """ 
    664702        # Must be version 3 for MyProxy 
    665703        context = SSL.Context(SSL.SSLv3_METHOD) 
    666704         
    667         if self.caCertFilePath or self.caCertDir: 
    668             context.load_verify_locations(self.caCertFilePath, self.caCertDir) 
    669              
     705        if verifyPeerWithTrustRoots: 
     706            context.load_verify_locations(None, self.caCertDir) 
     707            verifyMode = SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT 
     708        else: 
     709            log.warning("SSL Context verify mode set to SSL.VERIFY_NONE") 
     710            verifyMode = SSL.VERIFY_NONE 
     711             
     712        # Verify peer's (MyProxy server) certificate 
     713        context.set_verify(verifyMode, self.__serverSSLCertVerify) 
     714              
    670715        if certFile: 
    671716            try: 
     
    674719                                promptPassphraseTwice, 
    675720                                passphrase): 
     721                    """Private key file password callback function""" 
    676722                    if len(passphrase) > passphraseMaxLen: 
    677723                        log.error('Passphrase length %d is greater than the ' 
     
    691737                                               "connection [also check CA " 
    692738                                               "certificate settings]: %s" %  
    693                                                traceback.format_exc())  
    694              
    695         # Verify peer's (MyProxy server) certificate 
    696         context.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT,  
    697                            self.__serverSSLCertVerify)  
    698          
     739                                               traceback.format_exc()) 
    699740            
    700741        # Disable for compatibility with myproxy server (er, globus) 
     
    713754        @param nBitsForKey: number of bits for private key generation -  
    714755        default is 2048 
    715         @rtype: string 
     756        @rtype: OpenSSL.crypto.PKey 
    716757        @return: public/private key pair 
    717758        """ 
     
    731772        @type messageDigest: basestring 
    732773        @param messageDigest: message digest type - default is MD5 
    733         @rtype: tuple 
     774        @rtype: base string 
    734775        @return certificate request PEM text and private key PEM text 
    735776        """ 
     
    949990        private key is not password protected. 
    950991        """ 
    951         globusLoc = os.environ.get('GLOBUS_LOCATION') 
     992        globusLoc = os.environ.get(MyProxyClient.GLOBUS_LOCATION_ENVVARNAME) 
    952993        if not sslCertFile: 
    953994            if globusLoc: 
    954995                sslCertFile = os.path.join(globusLoc,  
    955                                             *MyProxyClient._hostCertSubDirPath) 
     996                                            *MyProxyClient.HOSTCERT_SUBDIRPATH) 
    956997                sslKeyFile = os.path.join(globusLoc,  
    957                                             *MyProxyClient._hostKeySubDirPath) 
     998                                            *MyProxyClient.HOSTKEY_SUBDIRPATH) 
    958999            else: 
    9591000                raise MyProxyClientError( 
     
    10111052        @return none 
    10121053        """ 
    1013         globusLoc = os.environ.get('GLOBUS_LOCATION') 
     1054        globusLoc = os.environ.get(MyProxyClient.GLOBUS_LOCATION_ENVVARNAME) 
    10141055        if not sslCertFile or not sslKeyFile: 
    10151056            if globusLoc: 
    10161057                sslCertFile = os.path.join(globusLoc,  
    1017                                          *MyProxyClient._hostCertSubDirPath) 
     1058                                           *MyProxyClient.HOSTCERT_SUBDIRPATH) 
    10181059                sslKeyFile = os.path.join(globusLoc,  
    1019                                          *MyProxyClient._hostKeySubDirPath) 
     1060                                          *MyProxyClient.HOSTKEY_SUBDIRPATH) 
    10201061            else: 
    10211062                raise MyProxyClientError( 
     
    10671108        @return none 
    10681109        """ 
    1069         globusLoc = os.environ.get('GLOBUS_LOCATION') 
     1110        globusLoc = os.environ.get(MyProxyClient.GLOBUS_LOCATION_ENVVARNAME) 
    10701111        if not sslCertFile or not sslKeyFile: 
    10711112            if globusLoc: 
    10721113                sslCertFile = os.path.join(globusLoc,  
    1073                                          *MyProxyClient._hostCertSubDirPath) 
     1114                                         *MyProxyClient.HOSTCERT_SUBDIRPATH) 
    10741115                sslKeyFile = os.path.join(globusLoc,  
    1075                                          *MyProxyClient._hostKeySubDirPath) 
     1116                                         *MyProxyClient.HOSTKEY_SUBDIRPATH) 
    10761117            else: 
    10771118                raise MyProxyClientError( 
     
    11531194            passphrase = str(passphrase) 
    11541195         
    1155         globusLoc = os.environ.get('GLOBUS_LOCATION') 
     1196        globusLoc = os.environ.get(MyProxyClient.GLOBUS_LOCATION_ENVVARNAME) 
    11561197        if not sslCertFile or not sslKeyFile: 
    11571198            if globusLoc: 
    11581199                sslCertFile = os.path.join(globusLoc,  
    1159                                          *MyProxyClient._hostCertSubDirPath) 
     1200                                           *MyProxyClient.HOSTCERT_SUBDIRPATH) 
    11601201                sslKeyFile = os.path.join(globusLoc,  
    1161                                          *MyProxyClient._hostKeySubDirPath) 
     1202                                          *MyProxyClient.HOSTKEY_SUBDIRPATH) 
    11621203            else: 
    11631204                # Default so that the owner is the same as the ID of the  
     
    12111252         
    12121253    def logon(self, username, passphrase, lifetime=None, keyPair=None,  
    1213               certReq=None, nBitsForKey=PRIKEY_NBITS): 
     1254              certReq=None, nBitsForKey=PRIKEY_NBITS, bootstrap=False, 
     1255              updateTrustRoots=False): 
    12141256        """Retrieve a proxy credential from a MyProxy server 
    12151257         
     
    12251267        @type lifetime: int 
    12261268        @param lifetime: lifetime for generated certificate 
     1269         
     1270        @type keyPair: OpenSSL.crypto.PKey 
     1271        @param keyPair: Public/Private key pair.  This is ignored if a  
     1272        certificate request is passed via the certReq keyword 
     1273         
     1274        @type certReq: string 
     1275        @param certReq: ASN1 format certificate request, if none set, one is  
     1276        created along with a key pair 
     1277         
     1278        @type nBitsForKey: int 
     1279        @param nBitsForKey: number of bits to use when generating key pair, 
     1280        defaults to the PRIKEY_NBITS class variable setting.  This keyword is 
     1281        ignored if a key pair is passed in from an external source via the 
     1282        keyPair keyword 
    12271283         
    12281284        @rtype: tuple 
     
    12301286        user certificate, it's private key and the issuing certificate.  The 
    12311287        issuing certificate is only set if the user certificate is a proxy 
     1288         
     1289        @type bootstrap: bool 
     1290        @param bootstrap: If set to True, bootstrap trust roots i.e. connect to 
     1291        MyProxy server without verification of the server's SSL certificate 
     1292        against any CA certificates.  Set to False, for default behaviour: 
     1293        verify server SSL certificate against CA certificates held in location 
     1294        set by the "caCertDir" attribute.  If bootstrap is set, updateTrustRoots 
     1295        will be forced to True also 
     1296         
     1297        @type updateTrustRoots: bool 
     1298        @param updateTrustRoots: set to True to update the trust roots 
    12321299        """ 
    1233          
     1300        if bootstrap: 
     1301            log.info('Bootstrapping MyProxy server root of trust.') 
     1302             
     1303            # Bootstrap implies update to trust roots 
     1304            updateTrustRoots = True 
     1305         
     1306        if updateTrustRoots: 
     1307            self.getTrustRoots(username,  
     1308                               passphrase,  
     1309                               writeToCACertDir=True,  
     1310                               bootstrap=bootstrap) 
     1311             
    12341312        lifetime = lifetime or self.proxyCertLifetime 
    12351313 
     
    12551333        # send get command - ensure conversion from unicode before writing 
    12561334        cmd = MyProxyClient.GET_CMD % (username, passphrase, lifetime) 
     1335             
    12571336        conn.write(str(cmd)) 
    1258      
     1337         
    12591338        # process server response 
    12601339        dat = conn.recv(MyProxyClient.SERVER_RESP_BLK_SIZE) 
     1340                    
    12611341        respCode, errorTxt = self._deserializeResponse(dat) 
    12621342        if respCode: 
     
    12781358        respCode, errorTxt = self._deserializeResponse(resp) 
    12791359        if respCode: 
    1280             raise MyProxyClientRetrieveError(errorTxt) 
     1360            raise MyProxyClientRetrieveError(errorTxt)      
    12811361     
    12821362        # deserialize certs from received cert data 
     
    13041384        return self.logon(*arg, **kw) 
    13051385     
    1306     def getTrustRoots(self, username='', passphrase=''): 
     1386    def getTrustRoots(self,  
     1387                      username='',  
     1388                      passphrase='',  
     1389                      writeToCACertDir=False, 
     1390                      bootstrap=False): 
    13071391        """Get trust roots for the given MyProxy server 
    13081392         
     
    13131397        @param passphrase: pass-phrase (optional) 
    13141398        server 
     1399         
     1400        @type writeToCACertDir: bool 
     1401        @param writeToCACertDir: if set to True, write the retrieved trust roots 
     1402        out to the directory specified by the "caCertDir" attribute 
     1403         
     1404        @type bootstrap: bool 
     1405        @param bootstrap: If set to True, bootstrap trust roots i.e. connect to 
     1406        MyProxy server without verification of the server's SSL certificate 
     1407        against any CA certificates.  Set to False, for default behaviour: 
     1408        verify server SSL certificate against CA certificates held in location 
     1409        set by the "caCertDir" attribute. 
    13151410         
    13161411        @return: trust root files as a dictionary keyed by file name with each  
     
    13181413        @rtype: dict 
    13191414        """ 
     1415        if bootstrap: 
     1416            log.info('Bootstrapping MyProxy server root of trust.') 
     1417             
    13201418        # Set-up SSL connection 
    1321         conn = self._initConnection() 
     1419        conn = self._initConnection(verifyPeerWithTrustRoots=(not bootstrap)) 
    13221420        conn.connect((self.hostname, self.port)) 
    13231421         
     
    13311429        # process server response chunks until all consumed 
    13321430        dat = '' 
     1431        tries = 0 
    13331432        try: 
    13341433            for tries in range(MyProxyClient.MAX_RECV_TRIES): 
     
    13441443                        MyProxyClient.MAX_RECV_TRIES, 
    13451444                        MyProxyClient.SERVER_RESP_BLK_SIZE) 
    1346              
     1445          
     1446        fieldName = MyProxyClient.TRUSTED_CERTS_FIELDNAME 
     1447        prefix = MyProxyClient.TRUSTED_CERTS_FILEDATA_FIELDNAME_PREFIX   
    13471448        respCode, errorTxt, fileData = self._deserializeResponse(dat,  
    1348                                                                 'TRUSTED_CERTS', 
    1349                                                                 'FILEDATA_') 
     1449                                                                 fieldName, 
     1450                                                                 prefix) 
    13501451        if respCode: 
    13511452            raise MyProxyClientGetTrustRootsError(errorTxt) 
    13521453         
    1353         filesDict = dict([(k, base64.b64decode(v))  
    1354                           for k, v in fileData.items() if k != 'TRUSTED_CERTS']) 
    1355          
     1454        filesDict = dict([(k.split(prefix, 1)[1], base64.b64decode(v))  
     1455                          for k, v in fileData.items() if k != fieldName]) 
     1456         
     1457        if writeToCACertDir: 
     1458            for fileName, fileContents in filesDict.items(): 
     1459                filePath = os.path.join(self.caCertDir, fileName) 
     1460                open(filePath, 'wb').write(fileContents) 
     1461                 
    13561462        return filesDict 
    13571463         
Note: See TracChangeset for help on using the changeset viewer.