Changeset 1857


Ignore:
Timestamp:
13/12/06 09:46:07 (13 years ago)
Author:
pjkersha
Message:

server/MyProxy.py: started integrating new version of MyProxy? client from
Tests/m2CryptoMyPxClnt.py. This version makes direct calls from python
over SSL to myproxy-server using M2Crypto

test/SessionMgrClientTest.py: change target uri for tests.

common/wsSecurity.py: set to sign BinarySecurityToken? element as well as
the message body.

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

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/Tests/Echo/wsSecurity.py

    r1824 r1857  
    191191         
    192192        # Leave out token 
    193         idNodes = [idNodes[1]] 
     193        #idNodes = [idNodes[1]] 
    194194 
    195195        # 1) Reference Generation 
     
    290290#         
    291291#        open('soap.xml', 'w').write(str(soapWriter)) 
    292 #        import pdb;pdb.set_trace()  
     292        import pdb;pdb.set_trace()  
    293293        print "Signature Generated" 
    294294        print str(soapWriter) 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/wsSecurity.py

    r1785 r1857  
    191191         
    192192        # Leave out token 
    193         idNodes = [idNodes[1]] 
     193        #idNodes = [idNodes[1]] 
    194194 
    195195        # 1) Reference Generation 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/MyProxy.py

    r1773 r1857  
    1 """NDG wrapper to MyProxy.  Also contains OpenSSLConfigFile class, a 
    2 wrapper to the openssl configuration file. 
     1"""MyProxy Client interface 
     2 
     3Based on original program myproxy_logon Tom Uram <turam@mcs.anl.gov> 
     4 
     5Also contains OpenSSLConfig class, a wrapper to the openssl configuration  
     6file. 
    37 
    48NERC Data Grid Project 
    59 
    6 P J Kershaw 02/06/05 
    7  
    8 Copyright (C) 2006 CCLRC & NERC 
    9  
    10 This software may be distributed under the terms of the Q Public License, 
    11 version 1.0 or later. 
     10@author P J Kershaw 02/06/05 
     11 
     12Major re-write to implement methods with SSL calls with M2Crypto rather use 
     13calls to myproxy client executables 
     14 
     15@copyright (C) 2006 CCLRC & NERC 
     16 
     17@license This software may be distributed under the terms of the Q Public  
     18License, version 1.0 or later. 
    1219""" 
    13  
    1420reposID = '$Id$' 
    1521 
    16 # Use pipes for stdin/stdout for MyProxy commands 
    1722import os 
    18  
    19 # Get hostname to check MyProxy server running on localhost 
    2023import socket 
    21  
    22 # Seeding for random number generator 
    23 import time 
    24  
    25 # Temporaries files created for MyProxy executables I/O 
    26 import tempfile 
    27  
    28 # Call MyProxy executables 
    29 from subprocess import * 
     24from M2Crypto import X509, RSA, EVP, m2, BIO 
     25from M2Crypto.SSL.Context import Context 
     26from M2Crypto.SSL.Connection import Connection 
    3027 
    3128import re 
    32  
    33 # Optionally include X509 certificate reading for addUser method 
    34 try: 
    35     from X509 import * 
    36 except: 
    37     pass 
    38  
    39 simpleCAdebug = False 
    40  
    41 # SimpleCA may be called locally or via Web Service 
    42 simpleCAImport = False 
    43 try: 
    44     # Using SimpleCA service local to current machine 
    45     from ca.SimpleCA import * 
    46     simpleCAImport = True 
    47     if simpleCAdebug: 
    48         print "SimpleCA loaded" 
    49      
    50 except ImportError, e: 
    51     if simpleCAdebug: 
    52         print "Skipping SimpleCA import: %s" % e 
    53     pass 
    54  
    55 try: 
    56     # Local SimpleCA not needed - may be using Web Service instead 
    57     from ndg.security.common.ca.SimpleCAClient import * 
    58     simpleCAImport = True 
    59     if simpleCAdebug: 
    60         print "SimpleCAClient loaded" 
    61      
    62 except ImportError, e: 
    63     if simpleCAdebug: 
    64         print "Skipping SimpleCAClient import: %s" % e 
    65     pass 
    66  
    67 if not simpleCAImport: 
    68     raise ImportError, \ 
    69         "Either SimpleCA or SimpleCAClient module must be present for MyProxy" 
     29import base64 
    7030 
    7131 
     
    7434 
    7535 
    76 #_____________________________________________________________________________ 
    77 class MyProxyError(Exception): 
    78      
    79     """Exception handling for NDG MyProxy class.""" 
    80      
    81     def __init__(self, msg): 
    82         self.__msg = msg 
    83           
    84     def __str__(self): 
    85         return self.__msg 
    86  
    87  
    88  
    89  
    90 #_____________________________________________________________________________ 
    91 class MyProxy: 
    92     """NDG wrapper to MyProxy server interface - use to serve proxy 
    93     certificate from user sign on""" 
     36 
     37class MyProxyClientError(Exception): 
     38    """Catch all exception class""" 
     39     
     40class GetError(Exception): 
     41    """Exceptions arising from get request to server""" 
     42     
     43class RetrieveError(Exception): 
     44    """Error recovering a response from MyProxy""" 
     45 
     46 
     47class MyProxyClient(object): 
     48    """MyProxy client interface  
     49     
     50    Based on protocol definitions in:  
     51     
     52    http://grid.ncsa.uiuc.edu/myproxy/protocol/ 
     53     
     54    @cvar __getCmd: get command string 
     55    @cvar __storeCmd: store command string 
     56    @cvar _certReqParamName: names of parameters needed to generate a  
     57    certificate request e.g. CN, OU etc. 
     58    """ 
     59       
     60    __getCmd="""VERSION=MYPROXYv2 
     61COMMAND=0 
     62USERNAME=%s 
     63PASSPHRASE=%s 
     64LIFETIME=%d\0""" 
     65  
     66    __infoCmd="""VERSION=MYPROXYv2 
     67COMMAND=2 
     68USERNAME=%s 
     69PASSPHRASE=PASSPHRASE 
     70LIFETIME=0""" 
     71  
     72    __destroyCmd="""VERSION=MYPROXYv2 
     73COMMAND=3 
     74USERNAME=%s 
     75PASSPHRASE=PASSPHRASE 
     76LIFETIME=0""" 
     77 
     78    __changePassphraseCmd="""VERSION=MYPROXYv2 
     79 COMMAND=4 
     80 USERNAME=%s 
     81 PASSPHRASE=%s 
     82 NEW_PHRASE=%s 
     83 LIFETIME=0""" 
     84    
     85    __storeCmd="""VERSION=MYPROXYv2 
     86COMMAND=5 
     87USERNAME=%s 
     88PASSPHRASE= 
     89LIFETIME=%d\0""" 
     90 
     91  
     92    _certReqParamName = ('O', 'OU') 
    9493 
    9594    # valid configuration property keywords 
     
    111110                        "localhost",  
    112111                        "127.0.0.1") 
    113      
    114      
    115     def __init__(self, propFilePath=None, **prop): 
    116         """Initialise proxy certificate generation settings 
    117  
     112 
     113    #_________________________________________________________________________             
     114    def __init__(self,  
     115                 propFilePath=None, 
     116                 hostname=os.environ.get('MYPROXY_SERVER'),  
     117                 port=7512, 
     118                 **prop): 
     119        """ 
     120        @param hostname string for MyProxy server - defaults to  
     121        MYPROXY_SERVER environment variable 
     122        @param integer port number MyProxy is running on 
    118123        propFilePath:   set properties via a configuration file 
    119         prop:           set properties via keywords""" 
     124        prop:           set properties via keywords 
     125        """ 
     126        self.hostname = hostname 
     127        self.port = port 
     128         
     129        # Set-up parameter names for certificate request 
     130        self.__certReqParam = {}.fromkeys(MyProxyClient._certReqParamName) 
     131         
     132        # Check for parameter names set from input 
     133        self.certReqParam = certReqKw 
    120134 
    121135 
    122136        self.__prop = {} 
    123  
    124          
    125         # Make a copy of the environment and then reset path restricting for 
    126         # use of MyProxy executables 
    127         # 
    128         # Use copy as direct assingment seems to take a reference to 
    129         # os.environ - if self.__env is changed, so is os.environ 
    130         self.__env = os.environ.copy() 
    131  
     137             
     138        
    132139        # Configuration file used to get default subject when generating a 
    133         # new certificate 
    134         self.__openSSLConf = OpenSSLConfigFile() 
     140        # new proxy certificate request 
     141        self.__openSSLConf = OpenSSLConfig() 
    135142 
    136143         
     
    144151         
    145152 
    146         # Grid security directory - environment setting overrides 
     153        # Grid security directory - environment variable setting overrides 
    147154        if 'GRID_SECURITY_DIR' in self.__env: 
    148155            self.__prop['gridSecurityDir'] = self.__env['GRID_SECURITY_DIR']             
    149156 
    150             openSSLConfFilePath = os.path.join(self.__prop['gridSecurityDir'], 
    151                                             self.__prop['openSSLConfFileName']) 
    152              
    153             self.__openSSLConf.setFilePath(openSSLConfFilePath) 
    154  
    155          
    156         if os.environ['GLOBUS_LOCATION'] is None: 
    157             raise MyProxyError(\ 
    158                         "Environment variable \"GLOBUS_LOCATION\" is not set") 
    159  
     157            self.__openSSLConf.filePath = \ 
     158                            os.path.join(self.__prop['gridSecurityDir'], 
     159                                         self.__prop['openSSLConfFileName']) 
    160160 
    161161        # Server host name - environment setting overrides 
    162162        if 'MYPROXY_SERVER' in self.__env: 
    163163            self.__prop['myProxyServer'] = self.__env['MYPROXY_SERVER']  
    164  
    165  
    166         # Executables - for getDelegation:   
    167         self.__getDelegExe = "myproxy-get-delegation" 
    168  
    169         # ... and for addUser: 
    170         self.__gridCertReqExe = 'openssl' 
    171         self.__adminLoadCredExe = 'myproxy-admin-load-credential' 
    172         self.__userIsRegExe = 'myproxy-admin-query' 
    173164            
    174165 
     
    178169        Check input keys are valid names""" 
    179170         
    180         for key in prop.keys(): 
    181             if key not in self.__validKeys: 
    182                 raise MyProxyError("Property name \"%s\" is invalid" % key) 
     171        invalidKeys = [key for key in prop if key not in self.__validKeys] 
     172        if invalidKeys: 
     173            raise MyProxyClientError, "Property name \"%s\" is invalid" % key 
    183174                 
    184175        self.__prop.update(prop) 
    185176 
    186  
    187         # Update path 
    188         if 'path' in prop: 
    189             self.__env['PATH'] = self.__prop['path'] 
    190  
    191177        # Update openssl conf file path 
    192178        if 'gridSecurityDir' in prop or 'openSSLConfFileName' in prop: 
    193179             
    194             openSSLConfFilePath = os.path.join(self.__prop['gridSecurityDir'], 
    195                                             self.__prop['openSSLConfFileName']) 
    196              
    197             self.__openSSLConf.setFilePath(openSSLConfFilePath) 
    198  
     180            self.__openSSLConf.filePath = \ 
     181                            os.path.join(self.__prop['gridSecurityDir'], 
     182                                         self.__prop['openSSLConfFileName']) 
     183             
    199184 
    200185    #_________________________________________________________________________ 
     
    214199                 
    215200            except IOError, e: 
    216                 raise MyProxyError(\ 
     201                raise MyProxyClientError(\ 
    217202                                "Error parsing properties file \"%s\": %s" % \ 
    218203                                (e.filename, e.strerror)) 
     
    220205                 
    221206            except Exception, e: 
    222                 raise MyProxyError("Error parsing properties file: %s" % \ 
     207                raise MyProxyClientError("Error parsing properties file: %s" % \ 
    223208                                    str(e)) 
    224209 
    225210        if propElem is None: 
    226             raise MyProxyError("Root element for parsing is not defined") 
     211            raise MyProxyClientError("Root element for parsing is not defined") 
    227212 
    228213 
     
    245230            tagElem = propElem.find('simpleCACltProp') 
    246231            if not tagElem: 
    247                 raise MyProxyError("Tag %s not found in file" % \ 
     232                raise MyProxyClientError("Tag %s not found in file" % \ 
    248233                                   'simpleCACltProp') 
    249234             
     
    253238                 
    254239            except Exception, e: 
    255                 raise MyProxyError("Setting SimpleCAClient properties: %s"%e) 
     240                raise MyProxyClientError("Setting SimpleCAClient properties: %s"%e) 
    256241 
    257242            prop['simpleCACltProp'] = simpleCAClt() 
     
    261246            tagElem = propElem.find('simpleCASrvProp') 
    262247            if not tagElem: 
    263                 raise MyProxyError("Tag %s not found in file" % \ 
     248                raise MyProxyClientError("Tag %s not found in file" % \ 
    264249                                   'simpleCASrvProp') 
    265250             
     
    269254                 
    270255            except Exception, e: 
    271                 raise MyProxyError("Setting SimpleCA properties: %s" % e) 
     256                raise MyProxyClientError("Setting SimpleCA properties: %s" % e) 
    272257 
    273258            prop['simpleCASrvProp'] = simpleCA() 
    274259 
    275260        else: 
    276             raise MyProxyError(\ 
     261            raise MyProxyClientError(\ 
    277262                "Neither %s or %s tags found in properties file" % \ 
    278263                ('simpleCACltProp', 'simpleCASrvProp')) 
     
    280265 
    281266        self.setProperties(**prop) 
    282  
    283  
    284     #_________________________________________________________________________ 
    285     def getDelegation(self, userName, passPhrase): 
    286         """Generate a proxy certificate given the MyProxy username and 
    287         passphrase""" 
    288  
    289         errMsgTmpl = "Getting delegation for %s: %s" 
    290  
    291              
    292         # Call proxy request command  
    293         try: 
    294             try: 
    295                 # Create a temporary to hold the proxy certificate file output 
    296                 proxyCertFile = tempfile.NamedTemporaryFile() 
    297  
    298                  
    299                 # Set up command + arguments 
    300                 # 
    301                 # TODO: -s <hostname> arg needed? - MYPROXY_SERVER environment 
    302                 # variable is set via __env 
    303                 # 
    304                 # P J Kershaw 27/06/05 
    305                 getDelegCmd = [self.__getDelegExe, 
    306                                '-S', 
    307                                '-s', self.__prop['myProxyServer'], 
    308                                '-l', userName, 
    309                                '-t', str(self.__prop['proxyCertLifetime']), 
    310                                '-o', proxyCertFile.name] 
    311  
    312                 # Open a pipe to send the pass phrase through stdin - avoid 
    313                 # exposing pass phrase as a command line arg for security 
    314                 getDelegPipeR, getDelegPipeW = os.pipe() 
    315                 os.write(getDelegPipeW, passPhrase) 
    316                  
    317                 getDelegProc = Popen(getDelegCmd, 
    318                                      stdin=getDelegPipeR, 
    319                                      stdout=PIPE, 
    320                                      stderr=PIPE, 
    321                                      close_fds=True, 
    322                                      env=self.__env)                 
    323             finally: 
    324                 try: 
    325                     os.close(getDelegPipeR) 
    326                     os.close(getDelegPipeW) 
    327                 except: pass 
    328  
    329  
    330             # File must be closed + close_fds set to True above otherwise 
    331             # wait() call will hang                 
    332             if getDelegProc.wait(): 
    333                 errMsg = getDelegProc.stderr.read() 
    334                 raise MyProxyError(errMsg) 
    335  
    336             # Get certificate created 
    337             sProxyCert = open(proxyCertFile.name).read() 
    338                 
    339         except IOError, e:                
    340             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    341          
    342         except OSError, e: 
    343             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    344          
    345         except Exception, e: 
    346             raise MyProxyError(errMsgTmpl % (userName, str(e))) 
    347  
    348  
    349         return sProxyCert 
    350  
    351  
    352     #_________________________________________________________________________ 
    353     def addUser(self, 
    354                 userName, 
    355                 userPassPhrase, 
    356                 cn=None, 
    357                 retDN=False, 
    358                 caPassPhrase=None, 
    359                 caConfigFilePath=None, 
    360                 **prop):         
    361         """Add a new user generating a new certificate and adding it to the 
    362         MyProxy repository 
    363  
    364         userName:                       user name or new user - must be unique 
    365                                         to the repository                                
    366         userPassPhrase:                 pass phrase to be used with the user 
    367                                         name 
    368         cn:                             Common name to be used on the 
    369                                         certificate to be generated 
    370                                  
    371         retDN:                          if set to True, return the 
    372                                         Distinguished Name for the new user. 
    373                                         By default, a dictionary is returned 
    374                                         containing a key, 'keyFile' set to the 
    375                                         text of the private key generated for 
    376                                         the new user.  If retDN is set too, 
    377                                         then an additional key 'dn' will be 
    378                                         included in the dictionary, set to the 
    379                                         DN for the new user. 
    380  
    381         caConfigFilePath|caPassPhrase:  pass phrase for SimpleCA's 
    382                                         certificate.  Set via file or direct 
    383                                         string input respectively.  Set here 
    384                                         to override setting [if any] made at 
    385                                         object creation. 
    386          
    387                                         Passphrase is only required if 
    388                                         SimpleCA is instantiated on the local 
    389                                         machine.  If SimpleCA WS is called no 
    390                                         passphrase is required. 
    391                                  
    392         **prop:                         keywords corresponding to 
    393                                         configuration properties normally set 
    394                                         in properties file.  Set here to 
    395                                         override. 
    396         """ 
    397  
    398         if not self.__myProxyServerAtLocalHost(): 
    399             raise NotImplementedError("addUser method must be called " + \ 
    400                                       "with MyProxy server set " + \ 
    401                                       "to the local host") 
    402          
    403          
    404         # Default Common name to the username 
    405         if cn is None: cn = userName 
    406  
    407              
    408         # Check user name doesn't already exist 
    409         if self.userIsRegistered(userName): 
    410             raise MyProxyError("Username '%s' already exists" % userName) 
    411  
    412  
    413         self.setProperties(**prop) 
    414  
    415  
    416         # addUSer returns a dictionary containing the key 'keyFile' which is 
    417         # the text of the private key generated by the certificate request 
    418         # but also, if the retDN input flag is set to True, a key 'dn' set to 
    419         # the distinguished name of the new user 
    420         user = {} 
    421  
    422  
    423         # Error message prefix for certificate request call 
    424         errMsgTmpl = "Certificate request for new user '%s': %s" 
    425  
    426  
    427         # Create certificate request and key files as temporary files.  Once 
    428         # the new certificate has been uploaded to the proxy server they may 
    429         # be discarded. 
    430         # 
    431         # Using NamedTemporaryFile, they are deleted when the temp file 
    432         # objects go out of scope 
    433         keyFile = tempfile.NamedTemporaryFile('w', -1, '.pem', 'key-', 
    434                                               self.__prop['tmpDir']) 
    435         certReqFile = tempfile.NamedTemporaryFile('w', -1, '.pem', 'certReq-', 
    436                                                   self.__prop['tmpDir']) 
    437  
    438  
    439         # Read default DN parameters from the Globud Open SSL configuration 
    440         # file 
    441         reqDN = self.__openSSLConf.getReqDN() 
    442  
    443         # Make into a string adding in the Common Name 
    444         reqDnTxt = \ 
    445 """%(0.organizationName)s 
    446 %(0.organizationalUnitName)s 
    447 """ % reqDN + cn + os.linesep 
    448  
    449  
    450         try: 
    451             try: 
    452                 # Open a pipe to send the required DN text in via stdin 
    453                 reqDnR, reqDnW = os.pipe() 
    454                 os.write(reqDnW, reqDnTxt) 
    455  
    456                 # Create a temporary file 
    457                 addUserTmp = tempfile.NamedTemporaryFile() 
    458                 open(addUserTmp.name, 'w').write(userPassPhrase) 
    459  
    460                 # Files to seed random number generation - this is a loose 
    461                 # copy of what grid-cert-request shell script does 
    462                 randFile = self.__mkRandTmpFile() 
    463                 randFileList = randFile.name + \ 
    464                                ":/var/adm/wtmp:/var/log/messages" 
    465                  
    466                 # Using openssl command rather than grid-cert-request wrapper 
    467                 # as latter doesn't include the command line options needed 
    468                 gridCertReqCmd = [self.__gridCertReqExe, 
    469                                   "req", 
    470                                   "-new", 
    471                                   "-keyout", keyFile.name, 
    472                                   "-out", certReqFile.name, 
    473                                   "-passout", "file:" + addUserTmp.name, 
    474                                   "-config", self.__openSSLConf.getFilePath(), 
    475                                   "-rand", randFileList] 
    476                  
    477                 gridCertReqProc = Popen(gridCertReqCmd, 
    478                                         stdin=reqDnR, 
    479                                         stdout=PIPE, 
    480                                         stderr=STDOUT, 
    481                                         close_fds=True, 
    482                                         env=self.__env) 
    483                  
    484                 if gridCertReqProc.wait(): 
    485                     errMsg = gridCertReqProc.stdout.read() 
    486                     raise MyProxyError(errMsg) 
    487  
    488             finally: 
    489                 try: 
    490                     os.close(reqDnR) 
    491                     os.close(reqDnW) 
    492  
    493                     # Read key file into string buffer to be returned 
    494                     user['keyFile'] = open(keyFile.name).read() 
    495                      
    496                     # Closing temporary files deletes them. 
    497                     addUserTmp.close() 
    498                     randFile.close() 
    499                 except: pass 
    500                  
    501         except IOError, e:                
    502             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    503          
    504         except OSError, e: 
    505             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    506          
    507         except Exception, e: 
    508             raise MyProxyError(errMsgTmpl % (userName, e)) 
    509  
    510          
    511         # Get the SimpleCA to sign the request - call locally or via WS 
    512         # depending on which properties were set 
    513         # WS call has precedence 
    514         if 'simpleCACltProp' in self.__prop:  
    515  
    516             # Client properties were set - initiate client to SimpleCA web 
    517             # service 
    518             try: 
    519                 simpleCAClt = SimpleCAClient(**self.__prop['simpleCACltProp']) 
    520                 sCert = simpleCAClt.reqCert(certReqFilePath=certReqFile.name) 
    521                  
    522             except Exception, e: 
    523                 raise MyProxyError("Calling SimpleCA WS for user '%s': %s" % \ 
    524                                    (userName, e)) 
    525              
    526         elif 'simpleCASrvProp' in self.__prop: 
    527              
    528             # Server properties were set - Create local instance SimpleCA 
    529             # server 
    530             try: 
    531                 simpleCA = SimpleCA(**self.__prop['simpleCASrvProp']) 
    532                 sCert = simpleCA.sign(certReqFilePath=certReqFile.name, 
    533                                       configFilePath=caConfigFilePath, 
    534                                       caPassPhrase=caPassPhrase) 
    535                  
    536             except Exception, e: 
    537                 raise MyProxyError("Calling SimpleCA for user '%s': %s" % \ 
    538                                    (userName, e)) 
    539         else: 
    540             raise MyProxyError(\ 
    541                 "Either Simple CA WS client or Simple CA server must be set") 
    542  
    543  
    544         # Copy new certificate into temporary file ready for call to load 
    545         # credential 
    546         certFile = tempfile.NamedTemporaryFile('r', -1, '.pem', 'cert-', 
    547                                                self.__prop['tmpDir']) 
    548         try: 
    549             open(certFile.name, "w").write(sCert) 
    550              
    551         except Exception, e: 
    552             raise MyProxyError(\ 
    553                         "Writing certificate temporary file \"%s\": %s" % \ 
    554                         (certFile.name, e)) 
    555          
    556         # Upload to MyProxy 
    557         errMsgTmpl = "Uploading certificate to MyProxy for new user '%s': %s" 
    558  
    559         adminLoadCredCmd = [self.__adminLoadCredExe, 
    560                             '-l', userName, 
    561                             '-c', certFile.name, 
    562                             '-y', keyFile.name, 
    563                             '-t', str(self.__prop['proxyCertMaxLifetime']), 
    564                             '-s', self.__prop['credStorageDir']] 
    565  
    566         try: 
    567             try: 
    568                 adminLoadCredProc = Popen(adminLoadCredCmd, 
    569                                           stdout=PIPE, 
    570                                           stderr=STDOUT, 
    571                                           env=self.__env) 
    572                  
    573                 if adminLoadCredProc.wait(): 
    574                     errMsg = adminLoadCredProc.stdout.read() 
    575                     raise MyProxyError(errMsg) 
    576             finally: 
    577                 try: 
    578                     keyFile.close() 
    579                 except: 
    580                     pass 
    581                  
    582         except IOError, e:                
    583             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    584          
    585         except OSError, e: 
    586             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    587          
    588         except Exception, e: 
    589             raise MyProxyError(errMsgTmpl % (userName, e)) 
    590  
    591  
    592         if retDN: 
    593             try: 
    594                 # Add an additional key to the dictionary output containing 
    595                 # the new user's DN 
    596                 user['dn'] = X509CertRead(certFile.name).dn.serialise() 
    597                  
    598             except Exception, e: 
    599                 raise MyProxyError(\ 
    600                     "Error returning DN for new certificate for user: " + \ 
    601                     userName) 
    602  
    603         return user 
    604  
    605      
    606     #_________________________________________________________________________ 
    607     def userIsRegistered(self, userName): 
    608         """Return True if given username is registered in the repository""" 
    609          
    610         if not self.__myProxyServerAtLocalHost(): 
    611             raise NotImplementedError("userIsRegistered method must " + \ 
    612                                       "be called with MyProxy server set " + \ 
    613                                       "to the local host") 
    614          
    615          
    616         errMsgTmpl = "Checking for user '%s': %s" 
    617         userIsRegCmd = [self.__userIsRegExe, 
    618                         '-l', userName, 
    619                         '-s', self.__prop['credStorageDir']] 
    620  
    621         try: 
    622             userIsRegProc = Popen(userIsRegCmd, stdout=PIPE, stderr=STDOUT) 
    623              
    624             if userIsRegProc.wait(): 
    625                 errMsg = userIsRegProc.stdout.read() 
    626                 raise MyProxyError(errMsg) 
    627              
    628             # Search for text matching expected output for username found 
    629             # Exit status from command seems to be 0 regardless of whether the 
    630             # username is found or not 
    631             outMsg = userIsRegProc.stdout.read() 
    632             if outMsg.find("username: " + userName) != -1: 
    633                 return True 
    634             else: 
    635                 return False 
    636                                         
    637         except IOError, e:                
    638             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    639          
    640         except OSError, e: 
    641             raise MyProxyError(errMsgTmpl % (userName, e.strerror)) 
    642          
    643         except Exception, e: 
    644             raise MyProxyError(errMsgTmpl % (userName, e)) 
    645  
    646  
    647     #_________________________________________________________________________         
    648     def __mkRandTmpFile(self): 
    649         """Make a file containing random data to seed the random number 
    650         generator used for the certificate request generation in addUser""" 
    651  
    652         randomTmpFile = tempfile.NamedTemporaryFile() 
    653  
    654         f = open(randomTmpFile.name, 'w') 
    655         f.write(os.urandom(1000)) 
    656         f.write(time.asctime()) 
    657         f.write(''.join(os.listdir(tempfile.tempdir))) 
    658         f.write(''.join(os.listdir(os.environ['HOME']))) 
    659         f.close() 
    660          
    661         return randomTmpFile 
    662267     
    663268 
     
    668273        addUser and userIsRegistered commands"""         
    669274        return self.__prop['myProxyServer'] in self.__class__.__localHostnames 
    670              
    671  
    672      
     275 
     276    #_________________________________________________________________________         
     277    def __setCertReqParam(self, dict): 
     278        '''certReqParam property set method - forces setting of certificate  
     279        request parameter names to valid values 
     280         
     281        @param dict: dictionary of parameters''' 
     282         
     283        invalidKw = [k for k in dict \ 
     284                     if k not in MyProxyClient._certReqParamName] 
     285        if invalidKw: 
     286            raise MyProxyClientError, \ 
     287    "Invalid certificate request keyword(s): %s.  Valid keywords are: %s" % \ 
     288    (', '.join(invalidKw), ', '.join(MyProxyClient._certReqParamName)) 
     289     
     290        self.__certReqParam.update(dict) 
     291 
     292    #_________________________________________________________________________         
     293    def __getCertReqParam(self): 
     294        """certReqParam property set method - for Certificate request  
     295        parameters dict""" 
     296        return self.__certReqParam 
     297     
     298     
     299    certReqParam = property(fset=__setCertReqParam, 
     300                            fget=__getCertReqParam, 
     301                            doc="Dictionary of parameters for cert. request") 
     302     
     303    #_________________________________________________________________________         
     304    def _createCertReq(self, CN, nBitsForKey=1024, messageDigest="md5"): 
     305        """ 
     306        Create a certificate request. 
     307         
     308        @param CN: Common Name for certificate - effectively the same as the 
     309        username for the MyProxy credential 
     310        @param nBitsForKey: number of bits for private key generation -  
     311        default is 1024 
     312        @param messageDigest: message disgest type - default is MD5 
     313        @return tuple of certificate request PEM text and private key PEM text 
     314        """ 
     315         
     316        # Check all required certifcate request DN parameters are set                 
     317        # Create certificate request 
     318        req = X509.Request() 
     319     
     320        # Generate keys 
     321        key = RSA.gen_key(nBitsForKey, m2.RSA_F4) 
     322     
     323        # Create public key object 
     324        pubKey = EVP.PKey() 
     325        pubKey.assign_rsa(key) 
     326         
     327        # Add the public key to the request 
     328        req.set_version(0) 
     329        req.set_pubkey(pubKey) 
     330         
     331        # Set DN 
     332        x509Name = X509.X509_Name() 
     333        x509Name.CN = CN 
     334        x509Name.OU = self.__certReqParam['OU'] 
     335        x509Name.O = self.__certReqParam['O'] 
     336        req.set_subject_name(x509Name) 
     337         
     338        req.sign(pubKey, messageDigest) 
     339         
     340        return (req.as_asn1(), key.as_pem(cipher=None)) 
     341     
     342     
     343    #_________________________________________________________________________            
     344    def _deserializeResponse(self, msg, *fieldNames): 
     345        """ 
     346        Deserialize a MyProxy server response 
     347         
     348        @param msg: string response message from MyProxy server 
     349        @*fieldNames: the content of additional fields can be returned by  
     350        specifying the field name or names as additional arguments e.g. info 
     351        method passes 'CRED_START_TIME', 'CRED_END_TIME' and 'CRED_OWNER' 
     352        field names.  The content of fields is returned as an extra element 
     353        in the tuple response.  This element is itself a dictionary indexed 
     354        by field name. 
     355        @return tuple of integer response and errorTxt string (if any) 
     356        """ 
     357         
     358        lines = msg.split('\n') 
     359         
     360        # get response value 
     361        responselines = filter(lambda x: x.startswith('RESPONSE'), lines) 
     362        responseline = responselines[0] 
     363        respCode = int(responseline.split('=')[1]) 
     364         
     365        # get error text 
     366        errorTxt = "" 
     367        errorlines = filter(lambda x: x.startswith('ERROR'), lines) 
     368        for e in errorlines: 
     369            etext = e.split('=', 1)[1] 
     370            errorTxt += etext 
     371         
     372        if fieldNames: 
     373            fields = {} 
     374                         
     375            for fieldName in fieldNames: 
     376                fieldlines = filter(lambda x: x.startswith(fieldName), lines) 
     377                try: 
     378                    # Nb. '1' arg to split ensures owner DN is not split up. 
     379                    field = fieldlines[0].split('=', 1)[1] 
     380                    fields[fieldName]=field.isdigit() and int(field) or field 
     381 
     382                except IndexError: 
     383                    # Ignore fields that aren't found 
     384                    pass 
     385                 
     386            return respCode, errorTxt, fields 
     387        else: 
     388            return respCode, errorTxt 
     389     
     390   
     391    #_________________________________________________________________________              
     392    def _deserializeCerts(self, inputDat): 
     393        """Unpack certificates returned from a get delegation call to the 
     394        server 
     395         
     396        @param inputDat: string containing the proxy cert and private key 
     397        and signing cert all in DER format 
     398         
     399        @return list containing the equivalent to the input in PEM format""" 
     400        pemCerts = []         
     401        dat = inputDat 
     402         
     403        while dat:     
     404            # find start of cert, get length         
     405            ind = dat.find('\x30\x82') 
     406            if ind < 0: 
     407                break 
     408                 
     409            len = 256*ord(dat[ind+2]) + ord(dat[ind+3]) 
     410     
     411            # extract der-format cert, and convert to pem 
     412            derCert = dat[ind:ind+len+4] 
     413             
     414            x509 = X509.load_cert_string(derCert, type=X509.TYPE_ASN1) 
     415            pemCert = x509.as_pem() 
     416             
     417            pemCerts.append(pemCert) 
     418     
     419            # trim cert from data 
     420            dat = dat[ind + len + 4:] 
     421            
     422        return pemCerts 
     423 
     424 
     425    #_________________________________________________________________________    
     426    def info(self, 
     427             username,  
     428             ownerCertFile=None, 
     429             ownerKeyFile=None, 
     430             ownerPassphrase=None): 
     431        """return True/False whether credentials exist on the server for a  
     432        given username 
     433         
     434        Exceptions:  GetError, StoreCredError 
     435         
     436        @param username: username selected for credential 
     437        @param ownerCertFile: certificate used for client authentication with 
     438        the MyProxy server SSL connection.  This ID will be set as the owner 
     439        of the stored credentials.  Only the owner can later remove  
     440        credentials with myproxy-destroy or the destroy method.  If not set, 
     441        this argument defaults to $GLOBUS_LOCATION/etc/hostcert.pem  
     442        @param ownerKeyFile: corresponding private key file.  See explanation 
     443        for ownerCertFile 
     444        @param ownerPassphrase: passphrase for ownerKeyFile.  Omit if the 
     445        private key is not password protected.   
     446        @return none 
     447        """ 
     448        globusLoc = os.environ.get('GLOBUS_LOCATION') 
     449        if not ownerCertFile or not ownerKeyFile: 
     450            if globusLoc: 
     451                ownerCertFile = os.path.join(globusLoc, 'etc', 'hostcert.pem') 
     452                ownerKeyFile = os.path.join(globusLoc, 'etc', 'hostkey.pem') 
     453            else: 
     454                raise MyProxyClientError, \ 
     455            "No client authentication cert. and private key file were given" 
     456         
     457 
     458        context = Context(protocol='sslv3') 
     459        context.load_cert(ownerCertFile, 
     460                          keyfile=ownerKeyFile, 
     461                          callback=lambda *ar, **kw: ownerPassphrase) 
     462     
     463        # Disable for compatibility with myproxy server (er, globus) 
     464        # globus doesn't handle this case, apparently, and instead 
     465        # chokes in proxy delegation code 
     466        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
     467         
     468        # connect to myproxy server 
     469        conn = Connection(context, sock=socket.socket()) 
     470         
     471        # Fudge to avoid checking client cert - seems to pick globus  
     472        # host/<hostname> one 
     473        conn.clientPostConnectionCheck = None 
     474        conn.connect((self.hostname, self.port)) 
     475         
     476        # send globus compatibility stuff 
     477        conn.write('0') 
     478     
     479        # send info command 
     480        cmd = MyProxyClient.__infoCmd % username 
     481        conn.write(cmd) 
     482     
     483        # process server response 
     484        dat = conn.recv(8192) 
     485          
     486        # Pass in the names of fields to return in the dictionary 'field'  
     487        respCode, errorTxt, field = self._deserializeResponse(dat,  
     488                                                         'CRED_START_TIME',  
     489                                                         'CRED_END_TIME',  
     490                                                         'CRED_OWNER') 
     491 
     492        return not bool(respCode), errorTxt, field 
     493 
     494 
     495    #_________________________________________________________________________    
     496    def changePassphrase(self, 
     497                         username,  
     498                         passphrase, 
     499                         newPassphrase, 
     500                         ownerCertFile=None, 
     501                         ownerKeyFile=None, 
     502                         ownerPassphrase=None): 
     503        """change pass-phrase protecting the credentials for a given username 
     504         
     505        Exceptions:  GetError, StoreCredError 
     506         
     507        @param username: username of credential 
     508        @param passphrase: existing pass-phrase for credential 
     509        @param newPassphrase: new pass-phrase to replace the existing one. 
     510        @param ownerCertFile: certificate used for client authentication with 
     511        the MyProxy server SSL connection.  This ID will be set as the owner 
     512        of the stored credentials.  Only the owner can later remove  
     513        credentials with myproxy-destroy or the destroy method.  If not set, 
     514        this argument defaults to $GLOBUS_LOCATION/etc/hostcert.pem  
     515        @param ownerKeyFile: corresponding private key file.  See explanation 
     516        for ownerCertFile 
     517        @param ownerPassphrase: passphrase for ownerKeyFile.  Omit if the 
     518        private key is not password protected.   
     519        @return none 
     520        """ 
     521        globusLoc = os.environ.get('GLOBUS_LOCATION') 
     522        if not ownerCertFile or not ownerKeyFile: 
     523            if globusLoc: 
     524                ownerCertFile = os.path.join(globusLoc, 'etc', 'hostcert.pem') 
     525                ownerKeyFile = os.path.join(globusLoc, 'etc', 'hostkey.pem') 
     526            else: 
     527                raise MyProxyClientError, \ 
     528            "No client authentication cert. and private key file were given" 
     529         
     530        import pdb;pdb.set_trace() 
     531        context = Context(protocol='sslv3') 
     532        context.load_cert(ownerCertFile, 
     533                          keyfile=ownerKeyFile, 
     534                          callback=lambda *ar, **kw: ownerPassphrase) 
     535     
     536        # Disable for compatibility with myproxy server (er, globus) 
     537        # globus doesn't handle this case, apparently, and instead 
     538        # chokes in proxy delegation code 
     539        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
     540         
     541        # connect to myproxy server 
     542        conn = Connection(context, sock=socket.socket()) 
     543         
     544        # Fudge to avoid checking client cert - seems to pick globus  
     545        # host/<hostname> one 
     546        conn.clientPostConnectionCheck = None 
     547        conn.connect((self.hostname, self.port)) 
     548         
     549        # send globus compatibility stuff 
     550        conn.write('0') 
     551     
     552        # send command 
     553        cmd = MyProxyClient.__changePassphraseCmd % (username,  
     554                                                     passphrase, 
     555                                                     newPassphrase) 
     556        conn.write(cmd) 
     557     
     558        # process server response 
     559        dat = conn.recv(8192) 
     560             
     561        respCode, errorTxt = self._deserializeResponse(dat) 
     562        if respCode: 
     563            raise GetError, errorTxt 
     564 
     565 
     566    #_________________________________________________________________________    
     567    def destroy(self, 
     568                username,  
     569                ownerCertFile=None, 
     570                ownerKeyFile=None, 
     571                ownerPassphrase=None): 
     572        """destroy credentials from the server for a given username 
     573         
     574        Exceptions:  GetError, StoreCredError 
     575         
     576        @param username: username selected for credential 
     577        @param ownerCertFile: certificate used for client authentication with 
     578        the MyProxy server SSL connection.  This ID will be set as the owner 
     579        of the stored credentials.  Only the owner can later remove  
     580        credentials with myproxy-destroy or the destroy method.  If not set, 
     581        this argument defaults to $GLOBUS_LOCATION/etc/hostcert.pem  
     582        @param ownerKeyFile: corresponding private key file.  See explanation 
     583        for ownerCertFile 
     584        @param ownerPassphrase: passphrase for ownerKeyFile.  Omit if the 
     585        private key is not password protected.   
     586        @return none 
     587        """ 
     588        globusLoc = os.environ.get('GLOBUS_LOCATION') 
     589        if not ownerCertFile or not ownerKeyFile: 
     590            if globusLoc: 
     591                ownerCertFile = os.path.join(globusLoc, 'etc', 'hostcert.pem') 
     592                ownerKeyFile = os.path.join(globusLoc, 'etc', 'hostkey.pem') 
     593            else: 
     594                raise MyProxyClientError, \ 
     595            "No client authentication cert. and private key file were given" 
     596         
     597 
     598        context = Context(protocol='sslv3') 
     599        context.load_cert(ownerCertFile, 
     600                          keyfile=ownerKeyFile, 
     601                          callback=lambda *ar, **kw: ownerPassphrase) 
     602     
     603        # Disable for compatibility with myproxy server (er, globus) 
     604        # globus doesn't handle this case, apparently, and instead 
     605        # chokes in proxy delegation code 
     606        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
     607         
     608        # connect to myproxy server 
     609        conn = Connection(context, sock=socket.socket()) 
     610         
     611        # Fudge to avoid checking client cert - seems to pick globus  
     612        # host/<hostname> one 
     613        conn.clientPostConnectionCheck = None 
     614        conn.connect((self.hostname, self.port)) 
     615         
     616        # send globus compatibility stuff 
     617        conn.write('0') 
     618     
     619        # send destroy command 
     620        cmd = MyProxyClient.__destroyCmd % username 
     621        conn.write(cmd) 
     622     
     623        # process server response 
     624        dat = conn.recv(8192) 
     625             
     626        respCode, errorTxt = self._deserializeResponse(dat) 
     627        if respCode: 
     628            raise GetError, errorTxt 
     629 
     630 
     631    #_________________________________________________________________________    
     632    def store(self, 
     633              username,  
     634              certFile, 
     635              keyFile, 
     636              ownerCertFile=None, 
     637              ownerKeyFile=None, 
     638              ownerPassphrase=None, 
     639              lifetime=43200): 
     640        """Upload credentials to the server 
     641         
     642        Exceptions:  GetError, StoreCredError 
     643         
     644        @param username: username selected for credential 
     645        @param certFile: user's X.509 certificate in PEM format 
     646        @param keyFile: equivalent private key file in PEM format 
     647        @param ownerCertFile: certificate used for client authentication with 
     648        the MyProxy server SSL connection.  This ID will be set as the owner 
     649        of the stored credentials.  Only the owner can later remove  
     650        credentials with myproxy-destroy or the destroy method.  If not set, 
     651        this argument defaults to $GLOBUS_LOCATION/etc/hostcert.pem or if this 
     652        is not set, certFile 
     653        @param ownerKeyFile: corresponding private key file.  See explanation 
     654        for ownerCertFile 
     655        @param ownerPassphrase: passphrase for ownerKeyFile.  Omit if the 
     656        private key is not password protected.  Nb. keyFile is expected to 
     657        be passphrase protected as this will be the passphrase used for 
     658        logon / getDelegation. 
     659        @return none 
     660        """ 
     661        globusLoc = os.environ.get('GLOBUS_LOCATION') 
     662        if not ownerCertFile or not ownerKeyFile: 
     663            if globusLoc: 
     664                ownerCertFile = os.path.join(globusLoc, 'etc', 'hostcert.pem') 
     665                ownerKeyFile = os.path.join(globusLoc, 'etc', 'hostkey.pem') 
     666            else: 
     667                ownerCertFile = certFile  
     668                ownerKeyFile = keyFile 
     669         
     670 
     671        context = Context(protocol='sslv3') 
     672        context.load_cert(ownerCertFile, 
     673                          keyfile=ownerKeyFile, 
     674                          callback=lambda *ar, **kw: ownerPassphrase) 
     675     
     676        # Disable for compatibility with myproxy server (er, globus) 
     677        # globus doesn't handle this case, apparently, and instead 
     678        # chokes in proxy delegation code 
     679        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
     680         
     681        # connect to myproxy server 
     682        conn = Connection(context, sock=socket.socket()) 
     683         
     684        # Fudge to avoid checking client cert - seems to pick globus  
     685        # host/<hostname> one 
     686        conn.clientPostConnectionCheck = None 
     687        conn.connect((self.hostname, self.port)) 
     688         
     689        # send globus compatibility stuff 
     690        conn.write('0') 
     691     
     692        # send store command 
     693        cmd = MyProxyClient.__storeCmd % (username, lifetime) 
     694        conn.write(cmd) 
     695     
     696        # process server response 
     697        dat = conn.recv(8192) 
     698             
     699        respCode, errorTxt = self._deserializeResponse(dat) 
     700        if respCode: 
     701            raise GetError, errorTxt 
     702         
     703        # Send certificate and private key 
     704        certTxt = X509.load_cert(certFile).as_pem() 
     705        keyTxt = open(keyFile).read() 
     706         
     707        conn.send(certTxt + keyTxt) 
     708     
     709     
     710        # process server response 
     711        resp = conn.recv(8192) 
     712        respCode, errorTxt = self._deserializeResponse(resp) 
     713        if respCode: 
     714            raise RetrieveError, errorTxt 
     715         
     716    #_________________________________________________________________________            
     717    def logon(self, username, passphrase, lifetime=43200): 
     718        """Retrieve a proxy credential from a MyProxy server 
     719         
     720        Exceptions:  GetError, RetrieveError 
     721         
     722        @param username: username of credential 
     723        @param passphrase: pass-phrase for private key of credential held on 
     724        server 
     725        @return list containing the credentials as strings in PEM format: the 
     726        proxy certificate, it's private key and the signing certificate. 
     727        """ 
     728     
     729        context = Context(protocol='sslv3') 
     730         
     731        # disable for compatibility with myproxy server (er, globus) 
     732        # globus doesn't handle this case, apparently, and instead 
     733        # chokes in proxy delegation code 
     734        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
     735         
     736        # connect to myproxy server 
     737        conn = Connection(context, sock=socket.socket()) 
     738         
     739        # Fudge to avoid checking client cert - seems to pick globus  
     740        # host/<hostname> one 
     741        conn.clientPostConnectionCheck = None 
     742        conn.connect((self.hostname, self.port)) 
     743         
     744        # send globus compatibility stuff 
     745        conn.write('0') 
     746     
     747        # send get command 
     748        cmd = MyProxyClient.__getCmd % (username,passphrase,lifetime) 
     749        conn.write(cmd) 
     750     
     751        # process server response 
     752        dat = conn.recv(8192) 
     753        respCode, errorTxt = self._deserializeResponse(dat) 
     754        if respCode: 
     755            raise GetError, errorTxt 
     756         
     757        # generate and send certificate request 
     758        # - The client will generate a public/private key pair and send a  
     759        #   NULL-terminated PKCS#10 certificate request to the server. 
     760        certReq, priKey = self._createCertReq(username) 
     761        conn.send(certReq) 
     762     
     763        # process certificates 
     764        # - 1 byte , number of certs 
     765        dat = conn.recv(1) 
     766        nCerts = ord(dat[0]) 
     767         
     768        # - n certs 
     769        dat = conn.recv(8192) 
     770     
     771        # process server response 
     772        resp = conn.recv(8192) 
     773        respCode, errorTxt = self._deserializeResponse(resp) 
     774        if respCode: 
     775            raise RetrieveError, errorTxt 
     776     
     777        # deserialize certs from received cert data 
     778        pemCerts = self._deserializeCerts(dat) 
     779        if len(pemCerts) != nCerts: 
     780            RetrieveError, "%d certs expected, %d received" % \ 
     781                                                    (nCerts, len(pemCerts)) 
     782     
     783        # write certs and private key to file 
     784        # - proxy cert 
     785        # - private key 
     786        # - rest of cert chain 
     787        creds = pemCerts[0]+priKey+''.join([cert for cert in pemCerts[1:]]) 
     788         
     789        return creds 
     790         
     791 
     792    def getDelegation(self, *arg, **kw): 
     793        """Retrieve proxy cert for user - same as logon""" 
     794        self.logon(*arg, **kw) 
     795 
     796 
    673797#_____________________________________________________________________________         
    674 class OpenSSLConfigFile: 
    675     """NDG Wrapper to OpenSSL Configuration file""" 
     798class OpenSSLConfigError(Exception): 
     799    """Exceptions related to OpenSSLConfig class"""    
     800 
     801 
     802#_____________________________________________________________________________         
     803class OpenSSLConfig(object): 
     804    """Wrapper to OpenSSL Configuration file to allow extraction of 
     805    required distinguished name used for making certificate requests 
     806     
     807    @cvar __reqDnRE: regular expression pattern for locating required 
     808    distinguished name from the config file""" 
    676809     
    677810    __reqDnRE = '\[ req_distinguished_name \].*\[' 
    678811     
    679812    def __init__(self, filePath=None): 
    680  
    681         self.setFilePath(filePath) 
    682  
    683              
    684     def setFilePath(self, filePath=None): 
    685         """Set file path for OpenSSL configuration file""" 
     813        """Initial OpenSSL configuration optionally setting a file path to 
     814        read from 
     815         
     816        @param filePath: path to OpenSSL configuration file""" 
     817        self.__setFilePath(filePath) 
     818 
     819             
     820    def __setFilePath(self, filePath): 
     821        """Set property method 
     822        @param filePath: path for OpenSSL configuration file""" 
    686823        if filePath is not None: 
    687824            if not isinstance(filePath, basestring): 
    688                 raise MyProxyError(\ 
    689                     "Input Grid Certificate file path must be a string") 
     825                raise OpenSSLConfigError, \ 
     826                    "Input OpenSSL config file path must be a string" 
    690827 
    691828            self.__filePath = filePath 
     
    693830            try: 
    694831                if not os.access(self.__filePath, os.R_OK): 
    695                     raise MyProxyError("not found or no read access") 
     832                    raise OpenSSLConfigError, "not found or no read access" 
    696833                                          
    697834            except Exception, e: 
    698                 raise MyProxyError(\ 
    699                     "Grid Certificate file path is not valid: \"%s\": %s" % \ 
    700                     (self.__filePath, str(e))) 
    701  
    702  
    703     def getFilePath(self): 
    704         """Get file path for OpenSSL configuration file""" 
     835                raise OpenSSLConfigError, \ 
     836                    "OpenSSL config file path is not valid: \"%s\": %s" % \ 
     837                    (self.__filePath, str(e)) 
     838 
     839 
     840    def __getFilePath(self): 
     841        """Get property method 
     842        @param filePath: file path for OpenSSL configuration file""" 
    705843        return self.__filePath 
    706844 
    707  
    708     def read(self): 
    709         """Read OpenSSL configuration file and return as string""" 
    710  
    711         file = open(self.__filePath, 'r') 
    712         fileTxt = file.read() 
    713         file.close() 
    714          
     845    filePath = property(fget=__getFilePath, 
     846                        fset=__setFilePath, 
     847                        doc="file path for configuration file") 
     848     
     849    def _read(self): 
     850        """Read OpenSSL configuration file and return as string 
     851         
     852        @return fileTxt: content of the file""" 
     853 
     854        fileTxt = open(self.__filePath).read() 
    715855        return fileTxt 
    716856 
     
    718858    def getReqDN(self): 
    719859        """Read Required DN parameters from the configuration file returning 
    720         them in a dictionary""" 
     860        them in a dictionary 
     861         
     862        @return required Distinguished Name as a dictionary""" 
    721863         
    722864        # Nb. Match over line boundaries 
    723         reqDnTxt = re.findall(self.__reqDnRE, self.read(), re.S)[0] 
     865        reqDnTxt = re.findall(self.__reqDnRE, self._read(), re.S)[0] 
    724866 
    725867        # Separate lines 
     
    731873        return dict([re.split('_default\s*=\s*', line) for line in reqDnLines\ 
    732874                     if re.match('[^#].*_default\s*=', line)])  
     875 
     876 
     877#_____________________________________________________________________________    
     878def main(): 
     879    import sys 
     880    import optparse 
     881    import getpass 
     882     
     883    parser = optparse.OptionParser() 
     884    parser.add_option("-i",  
     885                      "--info",  
     886                      dest="info",  
     887                      default=False, 
     888                      action="store_true", 
     889                      help="check whether a credential exists") 
     890 
     891    parser.add_option("-z",  
     892                      "--destroy",  
     893                      dest="destroy",  
     894                      default=False, 
     895                      action="store_true", 
     896                      help="destroy credential") 
     897 
     898    parser.add_option("-C",  
     899                      "--change-pass-phrase",  
     900                      dest="changePassphrase",  
     901                      default=False, 
     902                      action="store_true", 
     903                      help="change pass-phrase protecting credential") 
     904 
     905    parser.add_option("-g",  
     906                      "--get-delegation",  
     907                      dest="getDelegation",  
     908                      default=False, 
     909                      action="store_true", 
     910                      help="Get delegation / logon") 
     911     
     912    parser.add_option("-c",  
     913                      "--certfile",  
     914                      dest="certFile",  
     915                      default=None, 
     916                      help="Certificate to be stored") 
     917     
     918    parser.add_option("-y",  
     919                      "--keyfile",  
     920                      dest="keyFile",  
     921                      default=None, 
     922                      help="Private key to be stored") 
     923     
     924    parser.add_option("-w",  
     925                      "--keyfile-passphrase",  
     926                      dest="ownerPassphrase",  
     927                      default=None, 
     928                      help="Pass-phrase for Private key used for SSL client") 
     929 
     930    parser.add_option("-s",  
     931                      "--pshost",  
     932                      dest="host",  
     933                      help="The hostname of the MyProxy server to contact") 
     934     
     935    parser.add_option("-p",  
     936                      "--psport",  
     937                      dest="port",  
     938                      default=7512, 
     939                      type="int", 
     940                      help="The port of the MyProxy server to contact") 
     941     
     942    parser.add_option("-l",  
     943                      "--username",  
     944                      dest="username",  
     945                      help=\ 
     946    "The username with which the credential is stored on the MyProxy server") 
     947 
     948    parser.add_option("-o",  
     949                      "--out",  
     950                      dest="outfile",  
     951                      help=\ 
     952    "The username with which the credential is stored on the MyProxy server") 
     953 
     954    parser.add_option("-t",  
     955                      "--proxy-lifetime",  
     956                      dest="lifetime",  
     957                      default=43200, 
     958                      type="int", 
     959                      help=\ 
     960    "The username with which the credential is stored on the MyProxy server") 
     961 
     962    (options, args) = parser.parse_args() 
     963     
     964 
     965    # process options     
     966    username = options.username 
     967    if not username: 
     968        if sys.platform == 'win32': 
     969            username = os.environ["USERNAME"] 
     970        else: 
     971            import pwd 
     972            username = pwd.getpwuid(os.geteuid())[0] 
     973 
     974    hostname = options.host or os.environ.get('MYPROXY_SERVER') 
     975    myProxy = MyProxyClient(hostname=hostname, 
     976                            port=options.port, 
     977                            O='NDG', 
     978                            OU='BADC') 
     979     
     980    if options.getDelegation: 
     981                 
     982        outfile = options.outfile 
     983        if not outfile: 
     984            if sys.platform == 'win32': 
     985                outfile = 'proxy' 
     986            elif sys.platform in ['linux2','darwin']: 
     987                outfile = '/tmp/x509up_u%s' % (os.getuid()) 
     988     
     989        # Get MyProxy password 
     990        passphrase = getpass.getpass() 
     991             
     992        # Retrieve proxy cert 
     993        try: 
     994            creds = myProxy.logon(username,  
     995                                  passphrase,  
     996                                  lifetime=options.lifetime) 
     997            open(outfile, 'w').write(creds) 
     998            print "A proxy has been received for user %s in %s." % \ 
     999                (username, outfile) 
     1000             
     1001        except Exception,e: 
     1002            print "Error:", e 
     1003            sys.exit(1) 
     1004             
     1005    elif options.changePassphrase: 
     1006                 
     1007        # Get MyProxy password 
     1008        passphrase = getpass.getpass(\ 
     1009                     prompt='Enter (current) MyProxy pass phrase: ') 
     1010         
     1011        newPassphrase = getpass.getpass(\ 
     1012                                 prompt='Enter new MyProxy pass phrase: ') 
     1013         
     1014        if newPassphrase != getpass.getpass(\ 
     1015                     prompt='Verifying - Enter new MyProxy pass phrase: '): 
     1016            raise Exception, "Pass-phrases entered don't match" 
     1017         
     1018         
     1019        # Retrieve proxy cert 
     1020        try: 
     1021            myProxy.changePassphrase(username, 
     1022                             passphrase, 
     1023                             newPassphrase,  
     1024                             options.certFile, 
     1025                             options.keyFile, 
     1026                             ownerPassphrase=open('../tmp2').read().strip())             
     1027        except Exception,e: 
     1028            print "Error:", e 
     1029            sys.exit(1) 
     1030                 
     1031    elif options.info: 
     1032        try: 
     1033            credExists, errorTxt, fields = myProxy.info(username,  
     1034                             options.certFile, 
     1035                             options.keyFile, 
     1036                             ownerPassphrase=open('../tmp2').read().strip()) 
     1037            if credExists: 
     1038                print "username: %s" % username 
     1039                print "owner: %s" % fields['CRED_OWNER'] 
     1040                print "  time left: %d" % \ 
     1041                        (fields['CRED_END_TIME'] - fields['CRED_START_TIME']) 
     1042            else: 
     1043                ownerCert = X509.load_cert(options.certFile) 
     1044                ownerCertDN = '/' + \ 
     1045                    ownerCert.get_subject().as_text().replace(', ', '/') 
     1046                print "no credentials found for user %s, owner \"%s\"" % \ 
     1047                    (username, ownerCertDN) 
     1048 
     1049        except Exception, e: 
     1050            print "Error:", e 
     1051            sys.exit(1) 
     1052                 
     1053    elif options.destroy: 
     1054        try: 
     1055            myProxy.destroy(username,  
     1056                            ownerCertFile=options.certFile, 
     1057                            ownerKeyFile=options.keyFile, 
     1058                            ownerPassphrase=open('../tmp2').read().strip()) 
     1059            
     1060        except Exception, e: 
     1061            print "Error:", e 
     1062            sys.exit(1) 
     1063    else: 
     1064        try: 
     1065            myProxy.store(username,  
     1066                          options.certFile, 
     1067                          options.keyFile, 
     1068                          ownerCertFile=options.certFile, 
     1069                          ownerKeyFile=options.keyFile, 
     1070                          ownerPassphrase=open('../tmp2').read().strip(), 
     1071                          lifetime=options.lifetime) 
     1072            
     1073        except Exception, e: 
     1074            print "Error:", e 
     1075            sys.exit(1) 
     1076     
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/SessionMgrClientTest.py

    r1796 r1857  
    3030 
    3131        testConfig = {} 
    32         testConfig['smURI'] = 'https://glue.badc.rl.ac.uk/SessionManager'#'https://localhost:5700/SessionManager' 
    33         testConfig['smURI'] = 'https://192.100.78.199:5700/SessionManager' 
     32        #testConfig['smURI'] = 'https://192.100.78.199:5700/SessionManager' 
     33        #testConfig['smURI'] = 'http://glue.badc.rl.ac.uk/SessionManager' 
     34        #testConfig['smURI'] = 'https://glue.badc.rl.ac.uk/SessionManager' 
     35        #testConfig['smURI'] = 'https://localhost:5700/SessionManager' 
     36        #testConfig['smURI'] = 'https://192.100.78.135:5700/SessionManager' 
     37        testConfig['smURI'] = 'https://glue.badc.rl.ac.uk/SessionManager' 
    3438        testConfig['aaURI'] = 'https://localhost:5000/AttributeAuthority' 
    3539 
Note: See TracChangeset for help on using the changeset viewer.