Changeset 3085


Ignore:
Timestamp:
30/11/07 10:31:48 (12 years ago)
Author:
pjkersha
Message:

ndg.security.common/ndg/security/common/gatekeeperService/TestGatekeeperResrc.py: moved to new gatekeeper unit test package

Location:
TI12-security/trunk/python
Files:
1 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/gatekeeper.py

    r3081 r3085  
    1414__revision__ = "$Id:gatekeeper.py 3079 2007-11-30 09:39:46Z pjkersha $" 
    1515 
     16import logging 
     17log = logging.getLogger(__name__) 
     18 
    1619# For parsing of properties file 
    1720try: # python 2.5 
     
    310313        raise NotImplementedError( 
    311314            self.executeAccess.__doc__.replace('\n       ','')) 
    312      
    313              
     315    
     316     
     317import sys # tracefile config param may be set to e.g. sys.stderr 
     318import urllib2 
     319import socket 
     320 
     321from ndg.security.common.SessionMgr import SessionMgrClient, SessionNotFound,\ 
     322    SessionCertTimeError, SessionExpired, InvalidSession, \ 
     323    AttributeRequestDenied 
     324     
     325def HandleSecurity(*args): 
     326    return PullModelHandler(*args)() 
     327 
     328class URLCannotBeOpened(Exception): 
     329    """Raise from canURLBeOpened PullModelHandler class method 
     330    if URL is invalid - this method is used to check the AA 
     331    service""" 
     332 
     333class PullModelHandler(object): 
     334    """Make access control decision based on CSML constraint and user security 
     335    token""" 
     336     
     337    AccessAllowedMsg = "Access Allowed" 
     338    InvalidAttributeCertificate = \ 
     339            "The certificate containing your authorisation roles is invalid" 
     340    NotLoggedInMsg = 'Not Logged in' 
     341    SessionExpiredMsg = 'Session has expired.  Please re-login' 
     342    InvalidSessionMsg = 'Session is invalid.  Please try re-login' 
     343    InvalidSecurityCondition = 'Invalid Security Condition' 
     344 
     345    def __init__(self, uri, securityElement, securityTokens): 
     346        """Initialise settings for WS-Security and SSL for SOAP 
     347        call to Session Manager 
     348         
     349        @type uri: string 
     350        @param uri: URI corresponding to data granule ID 
     351         
     352        @type securityElement: ElementTree Element 
     353        @param securityElement: MOLES security constraint containing role and 
     354        Attribute Authority URI. In xml, could look like: 
     355        <moles:effect>allow</moles:effect> 
     356            <moles:simpleCondition> 
     357            <moles:dgAttributeAuthority>https://glue.badc.rl.ac.uk/AttributeAuthority</moles:dgAttributeAuthority> 
     358            <moles:attrauthRole>coapec</moles:attrauthRole> 
     359        </moles:simpleCondition> 
     360        NB: xmlns:moles="http://ndg.nerc.ac.uk/moles 
     361         
     362        @type: pylons.session 
     363        @param securityTokens: dict-like session object containing security  
     364        tokens""" 
     365         
     366        self.uri = uri 
     367        self.securityElement = securityElement 
     368        self.securityTokens = securityTokens 
     369 
     370 
     371    def __call__(self, **kw): 
     372        """Convenience wrapper for checkAccess""" 
     373        return self.checkAccess(**kw) 
     374 
     375 
     376    def checkAccess(self,  
     377                    uri=None,  
     378                    securityElement=None,  
     379                    securityTokens=None): 
     380        """Make an access control decision based on whether the user is 
     381        authenticated and has the required roles 
     382         
     383        @type uri: string 
     384        @param uri: URI corresponding to data granule ID 
     385         
     386        @type: ElementTree Element 
     387        @param securityElement: MOES security constraint containing role and 
     388        Attribute Authority URI. In xml, could look like: 
     389        <moles:effect>allow</moles:effect> 
     390            <moles:simpleCondition> 
     391            <moles:dgAttributeAuthority>https://glue.badc.rl.ac.uk/AttributeAuthority</moles:dgAttributeAuthority> 
     392            <moles:attrauthRole>coapec</moles:attrauthRole> 
     393        </moles:simpleCondition> 
     394        NB: xmlns:moles="http://ndg.nerc.ac.uk/moles" 
     395         
     396        @type: pylons.session 
     397        @param securityTokens: dict-like session object containing security  
     398        tokens.  Resets equivalent object attribute.""" 
     399           
     400        # tokens and element may be set from __init__ or as args to this  
     401        # method.  If the latter copy them into self   
     402        if uri: 
     403            self.uri = uri 
     404             
     405        if securityTokens: 
     406            self.securityTokens = securityTokens 
     407                             
     408        if securityElement: 
     409            self.securityElement=securityElement 
     410      
     411        # Check self.securityTokens - if not set then the user mustn't be  
     412        # logged in.  This situation is possible if a user has been denied 
     413        # access to data and then tried to logout - after log out they are 
     414        # redirected back to the page where they tried accessing data but this 
     415        # time they will have no security credential set 
     416        if not self.securityTokens: 
     417            # Try to recover and do something sensible 
     418            # 
     419            # TODO: this adds insult to injury if the person has just been 
     420            # denied access to data.  Instead do a redirect back to the  
     421            # discovery page? 
     422            # P J Kershaw 10/08/07 
     423            log.info("Exiting from Gatekeeper: user is not logged in") 
     424            return False, self.__class__.NotLoggedInMsg 
     425             
     426        xpathr='{http://ndg.nerc.ac.uk/moles}simpleCondition/{http://ndg.nerc.ac.uk/moles}attrauthRole' 
     427        xpathaa='{http://ndg.nerc.ac.uk/moles}simpleCondition/{http://ndg.nerc.ac.uk/moles}dgAttributeAuthority' 
     428        roleE,aaE=self.securityElement.find(xpathr),self.securityElement.find(xpathaa) 
     429        if roleE is None: 
     430            log.error("Gatekeeper: role not found in dataset element: %s" % \ 
     431                      self.securityElement) 
     432            return False, self.__class__.InvalidSecurityCondition 
     433         
     434        self.reqRole=roleE.text 
     435         
     436        # Check Attribute Authority address 
     437        try: 
     438            PullModelHandler.urlCanBeOpened(aaE.text) 
     439        except (URLCannotBeOpened, AttributeError): 
     440            # Catch situation where either Attribute Authority address in the 
     441            # data invalid or none was set.  In this situation verify 
     442            # against the Attribute Authority set in the config 
     443            log.info('Gatekeeper: Attribute Authority address is invalid ' + \ 
     444                     'in data "%s" - defaulting to config file setting' % \ 
     445                     self.securityElement) 
     446            self.reqAAURI = g.securityCfg.aaURI 
     447     
     448        # Create Session Manager client 
     449        self.smClnt = SessionMgrClient(uri=self.securityTokens['h'], 
     450                    sslCACertFilePathList=g.securityCfg.sslCACertFilePathList, 
     451                    sslPeerCertCN=g.securityCfg.sslPeerCertCN, 
     452                    signingCertFilePath=g.securityCfg.wssCertFilePath, 
     453                    signingPriKeyFilePath=g.securityCfg.wssPriKeyFilePath, 
     454                    signingPriKeyPwd=g.securityCfg.wssPriKeyPwd, 
     455                    caCertFilePathList=g.securityCfg.wssCACertFilePathList, 
     456                    tracefile=g.securityCfg.tracefile)        
     457         
     458        return self.__pullSessionAttCert() 
     459             
     460             
     461    def __pullSessionAttCert(self): 
     462        """Check to see if the Session Manager can deliver an Attribute  
     463        Certificate with the required role to gain access to the resource 
     464        in question""" 
     465             
     466        try: 
     467            # Make request for attribute certificate 
     468            attCert = self.smClnt.getAttCert(attAuthorityURI=self.reqAAURI, 
     469                                         sessID=self.securityTokens['sid'], 
     470                                         reqRole=self.reqRole) 
     471        except AttributeRequestDenied, e: 
     472            log.info(\ 
     473                "Gatekeeper - request for attribute certificate denied: %s"%e) 
     474            return False, str(e) 
     475         
     476        except SessionNotFound, e: 
     477            log.info("Gatekeeper - no session found: %s" % e) 
     478            return False, self.__class__.NotLoggedInMsg 
     479 
     480        except SessionExpired, e: 
     481            log.info("Gatekeeper - session expired: %s" % e) 
     482            return False, self.__class__.SessionExpiredMsg 
     483 
     484        except SessionCertTimeError, e: 
     485            log.info("Gatekeeper - session cert. time error: %s" % e) 
     486            return False, self.__class__.InvalidSessionMsg 
     487             
     488        except InvalidSession, e: 
     489            log.info("Gatekeeper - invalid user session: %s" % e) 
     490            return False, self.__class__.InvalidSessionMsg 
     491 
     492        except Exception, e: 
     493            raise GateKeeperError, "Gatekeeper request for attribute certificate: "+\ 
     494                            str(e) 
     495                             
     496        # Check attribute certificate is valid 
     497        attCert.certFilePathList = g.securityCfg.acCACertFilePathList 
     498        attCert.isValid(raiseExcep=True) 
     499             
     500        # Check it's issuer is as expected 
     501        if attCert.issuer != g.securityCfg.acIssuer: 
     502            log.info('Gatekeeper - access denied: Attribute Certificate ' + \ 
     503                'issuer DN, "%s" ' % attCert.issuer + \ 
     504                'must match this data provider\'s Attribute Authority ' + \ 
     505                'DN: "%s"' % g.securityCfg.acIssuer) 
     506            return False, self.__class__.InvalidAttributeCertificate 
     507         
     508        log.info('Gatekeeper - access granted for user "%s" '%attCert.userId+\ 
     509                 'to "%s" secured with role "%s" ' % (self.uri,self.reqRole)+\ 
     510                 'using attribute certificate:\n\n%s' % attCert) 
     511                      
     512        return True, self.__class__.AccessAllowedMsg 
     513 
     514    @classmethod 
     515    def urlCanBeOpened(cls, url, timeout=5, raiseExcep=True): 
     516       """Check url can be opened - adapted from  
     517       http://mail.python.org/pipermail/python-list/2004-October/289601.html 
     518       """ 
     519     
     520       found = False 
     521       defTimeOut = socket.getdefaulttimeout() 
     522       try: 
     523           socket.setdefaulttimeout(timeout) 
     524 
     525           try: 
     526               urllib2.urlopen(url) 
     527           except (urllib2.HTTPError, urllib2.URLError, 
     528                   socket.error, socket.sslerror): 
     529               if raiseExcep: 
     530                   raise URLCannotBeOpened 
     531            
     532           found = True 
     533          
     534       finally: 
     535           socket.setdefaulttimeout(defTimeOut) 
     536            
     537       return found 
     538    
     539 
     540class SecurityConfigError(Exception): 
     541    """Handle errors from parsing security config items""" 
     542        
     543class SecurityConfig(object): 
     544    """Get Security related parameters from the Pylons NDG config file""" 
     545     
     546    def parse(self, cfg, section='NDG_SECURITY'): 
     547        '''Get PKI settings for Attribute Authority and Session Manager from 
     548        the configuration file 
     549         
     550        @type cfg: ConfigParser object 
     551        @param cfg: reference to configuration file.''' 
     552         
     553        tracefileExpr = cfg.get(section, 'tracefile') 
     554        if tracefileExpr: 
     555            self.tracefile = eval(tracefileExpr) 
     556 
     557        self.smURI = cfg.get(section, 'sessionMgrURI')         
     558        self.aaURI = cfg.get(section, 'attAuthorityURI') 
     559 
     560        try: 
     561            self.wssCACertFilePathList = \ 
     562                cfg.get(section, 'wssCACertFilePathList').split() 
     563                 
     564        except AttributeError: 
     565            raise SecurityConfigError, \ 
     566                                'No "wssCACertFilePathList" security setting' 
     567 
     568        # Attribute Certificate Issuer 
     569        self.acIssuer = cfg.get(section, 'acIssuer') 
     570         
     571        # verification of X.509 cert back to CA 
     572        try: 
     573            self.acCACertFilePathList = cfg.get(section,  
     574                                            'acCACertFilePathList').split()           
     575        except AttributeError: 
     576            raise SecurityConfigError, \ 
     577                                'No "acCACertFilePathList" security setting' 
     578 
     579              
     580    def __repr__(self): 
     581        return '\n'.join(["%s=%s" % (k,v) for k,v in self.__dict__.items() \ 
     582                if k[:2] != "__"]) 
     583      
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/conf/attAuthority.tac

    r3040 r3085  
    1 #!/usr/bin/env python 
    21"""NDG Security Attribute Authority .tac file  
    32 
Note: See TracChangeset for help on using the changeset viewer.