Ignore:
Timestamp:
07/04/09 16:40:44 (11 years ago)
Author:
pjkersha
Message:

Added a Policy Information Point to encapsulate subject attribute retrieval.

Location:
TI12-security/trunk/python/ndg.security.common/ndg/security/common
Files:
4 edited

Legend:

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

    r4840 r5181  
    3636 
    3737 
    38 #_____________________________________________________________________________ 
    3938class AttCertError(Exception):   
    4039    """Exception handling for NDG Attribute Certificate class.""" 
    4140 
    42 #_____________________________________________________________________________ 
     41class AttCertNotBeforeTimeError(AttCertError): 
     42    """Current time is before the Attribute Certificate's not before time""" 
     43 
     44class AttCertExpired(AttCertError): 
     45    """Current time is after the Attribute Certificate's not after time""" 
     46 
    4347class AttCertReadOnlyDict(dict): 
    4448    def __init__(self, inputDict): 
     
    4650         
    4751    def __setitem__(self, key, item): 
    48         raise KeyError, "Items are read-only in this dictionary" 
     52        raise KeyError("Items are read-only in this dictionary") 
    4953        
    50 #_____________________________________________________________________________ 
    5154class _MetaAttCert(type): 
    5255    """Enable AttCert to have read only class variables e.g. 
     
    5861    ... raises - AttributeError: can't set attribute""" 
    5962     
    60     #_________________________________________________________________________     
    6163    def __getVersion(cls): 
    6264        '''Version of THIS format for the certificate''' 
     
    10411043        version (default is True) 
    10421044 
    1043         @param chkProvenanceset to True to check provenance value is valid 
     1045        @param chkProvenance: set to True to check provenance value is valid 
    10441046        (default is True) 
    10451047 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/msi.py

    r5168 r5181  
    8888        return resource 
    8989 
    90 class Subject(object): 
     90class _AttrDict(dict): 
     91    """Utility class for holding a constrained list of attributes governed 
     92    by a namespace list""" 
     93    namespaces = () 
     94    def __init__(self, **attributes): 
     95        invalidAttributes = [attr for attr in attributes \ 
     96                             if attr not in self.__class__.namespaces] 
     97        if len(invalidAttributes) > 0: 
     98            raise TypeError("The following attribute namespace(s) are not " 
     99                            "recognised: %s" % invalidAttributes) 
     100             
     101        self.update(attributes) 
     102 
     103    def __setitem__(self, key, val): 
     104        if key not in self.__class__.namespaces: 
     105            raise KeyError('Namespace "%s" not recognised.  Valid namespaces ' 
     106                           'are: %s' % self.__class__.namespaces) 
     107             
     108        dict.__setitem__(self, key, val) 
     109 
     110 
     111    def update(self, d, **kw):         
     112        for dictArg in (d, kw): 
     113            for k in dictArg: 
     114                if key not in self.__class__.namespaces: 
     115                    raise KeyError('Namespace "%s" not recognised.  Valid ' 
     116                                   'namespaces are: %s' % 
     117                                   self.__class__.namespaces) 
     118         
     119        dict.update(self, d, **kw) 
     120 
     121class Subject(_AttrDict): 
    91122    '''Subject designator''' 
    92     def __init__(self, attributes={}): 
    93         self.attributes = attributes 
    94  
    95 class Resource(object): 
     123    namespaces = ( 
     124        "urn:ndg:security:authz:1.0:attr:subject:userId", 
     125        "urn:ndg:security:authz:1.0:attr:subject:sessionId", 
     126        "urn:ndg:security:authz:1.0:attr:subject:sessionManagerURI", 
     127        "urn:ndg:security:authz:1.0:attr:subject:roles"         
     128    ) 
     129    (USERID_NS, SESSIONID_NS, SESSIONMANAGERURI_NS, ROLES_NS) = namespaces 
     130 
     131class Resource(_AttrDict): 
    96132    '''Resource designator''' 
    97     def __init__(self, uri=''): 
    98         self.uri = uri 
    99          
    100     def __str__(self): 
    101         return self.uri 
    102         
    103     def __eq__(self, uri): 
    104         return self.uri == uri 
    105      
     133    namespaces = ( 
     134        "urn:ndg:security:authz:1.0:attr:resource:uri", 
     135    ) 
     136    (URI_NS,) = namespaces 
     137            
    106138class Request(object): 
    107139    '''Request to send to a PDP''' 
     
    129161         
    130162         
     163from ndg.security.common.sessionmanager import SessionManagerClient, \ 
     164    SessionNotFound, SessionCertTimeError, SessionExpired, InvalidSession, \ 
     165    AttributeRequestDenied 
     166                     
     167from ndg.security.common.authz.pdp import PDPUserNotLoggedIn, \ 
     168    PDPUserAccessDenied 
     169     
     170class SubjectRetrievalError(Exception): 
     171    """Generic exception class for errors related to information about the 
     172    subject""" 
     173     
     174class InvalidAttributeCertificate(SubjectRetrievalError): 
     175    "The certificate containing authorisation roles is invalid" 
     176    def __init__(self, msg=None): 
     177        SubjectRetrievalError.__init__(self, msg or  
     178                                       InvalidAttributeCertificate.__doc__) 
     179         
     180class AttributeCertificateNotBeforeTimeError(SubjectRetrievalError): 
     181    ("There is a time issuing error with certificate containing authorisation " 
     182    "roles") 
     183    def __init__(self, msg=None): 
     184        SubjectRetrievalError.__init__(self, msg or  
     185                                AttributeCertificateNotBeforeTimeError.__doc__) 
     186         
     187class AttributeCertificateExpired(SubjectRetrievalError): 
     188    "The certificate containing authorisation roles has expired" 
     189    def __init__(self, msg=None): 
     190        SubjectRetrievalError.__init__(self, msg or  
     191                                       AttributeCertificateExpired.__doc__) 
     192             
     193class SessionExpiredMsg(SubjectRetrievalError): 
     194    'Session has expired.  Please re-login at your home organisation' 
     195    def __init__(self, msg=None): 
     196        SubjectRetrievalError.__init__(self, msg or SessionExpiredMsg.__doc__) 
     197 
     198class SessionNotFoundMsg(SubjectRetrievalError): 
     199    'No session was found.  Please try re-login with your home organisation' 
     200    def __init__(self, msg=None): 
     201        SubjectRetrievalError.__init__(self, msg or  
     202                                       SessionNotFoundMsg.__doc__) 
     203 
     204class InvalidSessionMsg(SubjectRetrievalError): 
     205    'Session is invalid.  Please try re-login with your home organisation' 
     206    def __init__(self, msg=None): 
     207        SubjectRetrievalError.__init__(self, msg or  
     208                                       InvalidSessionMsg.__doc__) 
     209 
     210class InitSessionCtxError(SubjectRetrievalError): 
     211    'A problem occurred initialising a session connection' 
     212    def __init__(self, msg=None): 
     213        SubjectRetrievalError.__init__(self, msg or  
     214                                       InitSessionCtxError.__doc__) 
     215 
     216class AttributeCertificateRequestError(SubjectRetrievalError): 
     217    'A problem occurred requesting a certificate containing authorisation roles' 
     218    def __init__(self, msg=None): 
     219        SubjectRetrievalError.__init__(self,msg or  
     220                                    AttributeCertificateRequestError.__doc__) 
     221 
     222class PIPAttributeQuery(_AttrDict): 
     223    namespaces = ( 
     224        "urn:ndg:security:authz:1.0:attr:subject", 
     225        "urn:ndg:security:authz:1.0:attr:attributeAuthorityURI", 
     226    )   
     227    (SUBJECT_NS, ATTRIBUTEAUTHORITY_NS) = namespaces     
     228 
     229class PIPAttributeResponse(_AttrDict): 
     230    namespaces = ( 
     231        "urn:ndg:security:authz:1.0:attr:attributeCertificate", 
     232    ) 
     233    (ATTRIBUTECERTIFICATE_NS,) = namespaces 
     234 
     235 
     236from ndg.security.common.wssecurity import WSSecurityConfig 
     237from ndg.security.common.credentialwallet import CredentialWallet 
     238 
     239class PIP(object): 
     240    """Policy Information Point - this implementation enables the PDP to  
     241    retrieve attributes about the Subject""" 
     242 
     243    def __init__(self, prefix='', **cfg): 
     244        '''Set-up WS-Security and SSL settings for connection to an 
     245        Attribute Authority 
     246         
     247        @type **cfg: dict 
     248        @param **cfg: keywords including 'sslCACertFilePathList' used to set a 
     249        list of CA certificates for an SSL connection to the Attribute 
     250        Authority if used and also WS-Security settings as used by 
     251        ndg.security.common.wssecurity.WSSecurityConfig 
     252        ''' 
     253        self._subjectCache = {} 
     254         
     255        self.wssecurityCfg = WSSecurityConfig() 
     256        wssePrefix = prefix + 'wssecurity' 
     257        self.wssecurityCfg.update(cfg, prefix=wssePrefix) 
     258                  
     259        self.sslCACertFilePathList = cfg.get(prefix+'sslCACertFilePathList',[]) 
     260 
     261    def attributeQuery(self, attributeQuery): 
     262        """Query the Attribute Authority specified in the request to retrieve 
     263        the attributes if any corresponding to the subject 
     264         
     265        @type attributeResponse: PIPAttributeQuery 
     266        @param attributeResponse:  
     267        @rtype: PIPAttributeResponse 
     268        @return: response containing the attributes retrieved from the 
     269        Attribute Authority""" 
     270         
     271        subject = attributeQuery[PIPAttributeQuery.SUBJECT_NS] 
     272        sessionId = subject[Subject.SESSIONID_NS] 
     273        attributeAuthorityURI = attributeQuery[ 
     274                                    PIPAttributeQuery.ATTRIBUTEAUTHORITY_NS] 
     275         
     276        # Check this subject's cache for an Attribute Certificate previously 
     277        # retrieved. 
     278        attributeCertificate = None 
     279        if self._subjectCache.get(sessionId) is not None: 
     280            subjectCred = subjectCache.credentialByURI.get( 
     281                                                        attributeAuthorityURI) 
     282             
     283            if subjectCred is not None: 
     284                if subjectCred['attCert'].isValid(): 
     285                    attributeCertificate = subjectCred['attCert'] 
     286         
     287        # If no Attribute Certificate is available, retrieve from the relevant 
     288        # Attribute Authority       
     289        if attributeCertificate is None:   
     290            sessionId = subject[Subject.SESSIONID_NS] 
     291            attributeCertificate = self._getAttributeCertificate( 
     292                                        sessionId, 
     293                                        subject[Subject.SESSIONMANAGERURI_NS], 
     294                                        attributeAuthorityURI) 
     295             
     296            # Make a new wallet for this subject 
     297            self._subjectCache[sessionId] = \ 
     298                        CredentialWallet(userId=attributeCertificate.userId) 
     299                         
     300            self._subjectCache[sessionId].addCredential( 
     301                                attributeCertificate, 
     302                                attributeAuthorityURI=attributeAuthorityURI) 
     303 
     304        attributeResponse = PIPAttributeResponse() 
     305        attributeResponse[PIPAttributeResponse.ATTRIBUTECERTIFICATE_NS] = \ 
     306                                                        attributeCertificate 
     307          
     308        return attributeResponse 
     309     
     310     
     311    def _getAttributeCertificate(self,  
     312                                 sessionId, 
     313                                 sessionManagerURI, 
     314                                 attributeAuthorityURI): 
     315        '''Retrieve an Attribute Certificate using the subject's Session 
     316        Manager 
     317         
     318        @type sessionId: basestring 
     319        @param sessionId: Session Manager session handle 
     320        @type sessionManagerURI: basestring 
     321        @param sessionManagerURI: URI to remote session manager service 
     322        @type attributeAuthorityURI: basestring 
     323        @param attributeAuthorityURI: URI to Attribute Authority service 
     324        ''' 
     325         
     326        try: 
     327            # Create Session Manager client - if a file path was set, setting 
     328            # are read from a separate config file section otherwise, from the 
     329            # PDP config object 
     330            smClnt = SessionManagerClient( 
     331                            uri=sessionManagerURI, 
     332                            sslCACertFilePathList=self.sslCACertFilePathList, 
     333                            cfg=self.wssecurityCfg) 
     334        except Exception, e: 
     335            log.error("Creating Session Manager client: %s" % e) 
     336            raise InitSessionCtxError() 
     337         
     338          
     339        try: 
     340            # Make request for attribute certificate 
     341            attCert = smClnt.getAttCert( 
     342                                attributeAuthorityURI=attributeAuthorityURI, 
     343                                sessID=sessionId) 
     344         
     345        except AttributeRequestDenied, e: 
     346            log.error("Request for attribute certificate denied: %s" % e) 
     347            raise PDPUserAccessDenied() 
     348         
     349        except SessionNotFound, e: 
     350            log.error("No session found: %s" % e) 
     351            raise SessionNotFoundMsg() 
     352 
     353        except SessionExpired, e: 
     354            log.error("Session expired: %s" % e) 
     355            raise SessionExpiredMsg() 
     356 
     357        except SessionCertTimeError, e: 
     358            log.error("Session cert. time error: %s" % e) 
     359            raise InvalidSessionMsg() 
     360             
     361        except InvalidSession, e: 
     362            log.error("Invalid user session: %s" % e) 
     363            raise InvalidSessionMsg() 
     364 
     365        except Exception, e: 
     366            log.error("Request from Session Manager [%s] to Attribute " 
     367                      "Authority [%s] for attribute certificate: %s: %s" %  
     368                      (sessionManagerURI, 
     369                       attributeAuthorityURI, 
     370                       e.__class__, e)) 
     371            raise AttributeCertificateRequestError() 
     372         
     373        try: 
     374            attCert.isValid(raiseExcep=True) 
     375         
     376        except AttCertNotBeforeTimeError, e:    
     377            log.exception(e) 
     378            raise AttributeCertificateNotBeforeTimeError() 
     379         
     380        except AttCertExpired, e:    
     381            log.exception(e) 
     382            raise AttributeCertificateExpired() 
     383 
     384        except AttCertError, e: 
     385            log.exception(e) 
     386            raise InvalidAttributeCertificate() 
     387             
     388        return attCert 
     389 
     390            
     391            
    131392class PDP(object): 
    132     def __init__(self, policyFilePath): 
     393    """Policy Decision Point""" 
     394     
     395    def __init__(self, policyFilePath=Policy(), pip=None): 
     396        """Read in a file which determines access policy""" 
    133397        self.policy = Policy.Parse(policyFilePath) 
     398        self.pip = pip 
    134399         
    135400    def evaluate(self, request): 
    136401        '''Make access control decision''' 
    137              
    138         for attr in request.resource.attributes: 
    139             if attr in request.subject.attributes: 
     402         
     403        # Look for matching targets to the given resource 
     404        resourceURI = request.resource[Resource.URI_NS] 
     405        matchingTargets = [target for target in self.policy.targets  
     406                           if target.regEx.match(resourceURI) is not None] 
     407         
     408        knownAttributeAuthorityURIs = [] 
     409        for matchingTarget in matchingTargets: 
     410             
     411            # Make call to the Policy Information Point to pull user 
     412            # attributes applicable to this resource 
     413            if matchingTarget.attributeAuthorityURI not in \ 
     414               knownAttributeAuthorityURIs: 
     415                 
     416                attributeQuery = PIPAttributeQuery() 
     417                attributeQuery[PIPAttributeQuery.SUBJECT_NS]=request.subject 
     418                 
     419                attributeQuery[PIPAttributeQuery.ATTRIBUTEAUTHORITY_NS] = \ 
     420                                        matchingTarget.attributeAuthorityURI 
     421                 
     422                attributeResponse = self.pip.attributeQuery(attributeQuery) 
     423                knownAttributeAuthorityURIs.append( 
     424                                        matchingTarget.attributeAuthorityURI) 
     425                 
     426                attributeCertificate = attributeResponse[ 
     427                                PIPAttributeResponse.ATTRIBUTECERTIFICATE_NS] 
     428                request.subject[Subject.ROLES_NS] = attributeCertificate.roles  
     429                
     430        # Match the subject's attributes against the target 
     431        for attr in matchingTarget.attributes: 
     432            if attr in request.subject[Subject.ROLES_NS]: 
    140433                return Response(Response.DECISION_PERMIT) 
    141434             
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/credentialwallet.py

    r5063 r5181  
    305305        '_cfg', 
    306306        '_credentials', 
     307        '_credentialsKeyedByURI', 
    307308        '_dn', 
    308309        '_attributeAuthorityURI' 
     
    413414            self.audit() 
    414415 
     416    def __getstate__(self): 
     417        '''Enable pickling for use with beaker.session''' 
     418        return dict([(attrName, getattr(self, attrName)) \ 
     419                     for attrName in CredentialWallet._protectedAttrs]) 
     420         
     421    def __setstate__(self): 
     422        '''Enable pickling for use with beaker.session''' 
     423        pass 
     424     
    415425    def parseConfig(self, cfg, prefix='', section='DEFAULT'): 
    416426        '''Extract parameters from _cfg config object''' 
     
    631641         
    632642    def _getCredentials(self): 
    633         """Get Property method.  Credentials are read-only 
     643        """Get Property method.  Credentials doct is read-only but also see  
     644        addCredential method 
    634645         
    635646        @rtype: dict 
     
    642653                               "issuing authorities") 
    643654 
    644  
     655    def _getCredentialsKeyedByURI(self): 
     656        """Get Property method for credentials keyed by Attribute Authority URI 
     657        Credentials dict is read-only but also see addCredential method 
     658         
     659        @rtype: dict 
     660        @return: cached ACs indexed by issuing Attribute Authority""" 
     661        return self._credentialsKeyedByURI 
     662     
     663    # Publish attribute 
     664    credentialsKeyedByURI = property(fget=_getCredentials, 
     665                           doc="List of Attribute Certificates linked to " 
     666                               "attribute authority URI") 
     667         
    645668    def _getCACertFilePathList(self): 
    646669        """Get CA cert or certs used to validate AC signatures and signatures 
     
    845868 
    846869 
    847     def addCredential(self, attCert, bUpdateCredentialRepository=True): 
     870    def addCredential(self,  
     871                      attCert,  
     872                      attributeAuthorityURI=None, 
     873                      bUpdateCredentialRepository=True): 
    848874        """Add a new attribute certificate to the list of credentials held. 
    849875 
    850876        @type attCert: 
    851877        @param attCert: new attribute Certificate to be added 
     878        @type attributeAuthorityURI: basestring 
     879        @param attributeAuthorityURI: input the Attribute Authority URI from 
     880        which attCert was retrieved.  This is added to a dict to enable access 
     881        to a given Attribute Certificate keyed by Attribute Authority URI.  
     882        See the getCredential method. 
    852883        @type bUpdateCredentialRepository: bool 
    853884        @param bUpdateCredentialRepository: if set to True, and a repository  
     
    857888        @return: True if certificate was added otherwise False.  - If an 
    858889        existing certificate from the same issuer has a later expiry it will 
    859         take precence and the new input certificate is ignored.""" 
     890        take precedence and the new input certificate is ignored.""" 
    860891 
    861892        # Check input 
    862893        if not isinstance(attCert, AttCert): 
    863             raise CredentialWalletError("Attribute Certificate must be an AttCert " 
    864                                   "type object") 
     894            raise CredentialWalletError("Attribute Certificate must be an " 
     895                                        "AttCert type object") 
    865896 
    866897        # Check certificate validity 
     
    897928            # from the CredentialRepository during creation of the wallet will 
    898929            # have +ve IDs previously allocated by the database 
    899             self._credentials[issuerName] = {'id': -1, 'attCert': attCert} 
    900  
     930            self._credentials[issuerName] = { 
     931                'id': -1,  
     932                'attCert': attCert, 
     933                'attributeAuthorityURI': attributeAuthorityURI 
     934            } 
     935 
     936            if attributeAuthorityURI: 
     937                self._credentialsKeyedByURI[attributeAuthorityURI] = \ 
     938                    self._credentials[issuerName] 
     939             
    901940            # Update the Credentials Repository - the permanent store of user 
    902941            # authorisation credentials.  This allows credentials for previous 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/signaturehandler/__init__.py

    r5168 r5181  
    238238            self.cfg = cfg 
    239239        else: 
    240             raise TypeError("cfg keyword set to %s type.  cfg must be a " 
    241                             "file path string, RawConfigParser derived " 
    242                             "class instance or WSSecurityConfig type" % 
    243                             cfg.__class__) 
    244  
     240            self.cfg = cfgClass() 
     241                 
    245242        # Also update config from keywords set  
    246         log.debug("BaseSignatureHandler.__init__: setting config from " 
     243        log.debug("BaseSignatureHandler.__init__: updating config from " 
    247244                  "keywords...") 
    248245         
Note: See TracChangeset for help on using the changeset viewer.