source: TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/authz/pip/esginterface.py @ 7155

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/authz/pip/esginterface.py@7155
Revision 7155, 7.2 KB checked in by pjkersha, 9 years ago (diff)

Incomplete - task 2: XACML-Security Integration

  • migrating to ndg.saml and ndg.soap imports now that SAML WSGI middleware has moved to ndg.saml egg.
  • Property svn:keywords set to Id
Line 
1"""PIP with interface to SAML 2.0 Attribute Authority as used with ESG
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "19/02/10"
7__copyright__ = "(C) 2010 Science and Technology Facilities Council"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = "$Id$"
12import traceback
13import logging
14log = logging.getLogger(__name__)
15
16from os import path
17from ConfigParser import ConfigParser
18
19from ndg.security.common.utils.configfileparsers import \
20                                            CaseSensitiveConfigParser
21from ndg.saml.saml2.binding.soap.client.attributequery import \
22                                            AttributeQuerySslSOAPBinding
23from ndg.security.common.X509 import X509Cert
24from ndg.security.common.authz import Subject
25from ndg.security.common.authz.pip import (PIPBase, PIPAttributeQuery, 
26                                           PIPAttributeResponse)
27   
28   
29class PIP(PIPBase):
30    """Policy Information Point to query ESG Attribute Authority for user
31    attributes
32    """
33    # Subject attributes makes no sense for external configuration - these
34    # are set at run time based on the given subject identity
35    DISALLOWED_ATTRIBUTE_QUERY_OPTNAMES = (
36        AttributeQuerySslSOAPBinding.SUBJECT_ID_OPTNAME,
37    )
38    ATTRIBUTE_QUERY_ATTRNAME = 'attributeQuery'
39    LEN_ATTRIBUTE_QUERY_ATTRNAME = len(ATTRIBUTE_QUERY_ATTRNAME)
40   
41    __slots__ = ('__attributeQueryBinding')
42   
43    def __init__(self):
44        '''Initialise settings for connection to an Attribute Authority'''
45        self.__attributeQueryBinding = AttributeQuerySslSOAPBinding()   
46
47    @classmethod
48    def fromConfig(cls, cfg, **kw):
49        '''Alternative constructor makes object from config file settings
50        @type cfg: basestring /ConfigParser derived type
51        @param cfg: configuration file path or ConfigParser type object
52        @rtype: ndg.saml.saml2.binding.soap.client.SOAPBinding
53        @return: new instance of this class
54        '''
55        obj = cls()
56        obj.parseConfig(cfg, **kw)
57       
58        return obj
59
60    def parseConfig(self, cfg, prefix='', section='DEFAULT'):
61        '''Read config settings from a file, config parser object or dict
62        @type cfg: basestring / ConfigParser derived type / dict
63        @param cfg: configuration file path or ConfigParser type object
64        @type prefix: basestring
65        @param prefix: prefix for option names e.g. "attributeQuery."
66        @type section: baestring
67        @param section: configuration file section from which to extract
68        parameters.
69        ''' 
70        if isinstance(cfg, basestring):
71            cfgFilePath = path.expandvars(cfg)
72            _cfg = CaseSensitiveConfigParser()
73            _cfg.read(cfgFilePath)
74            items = _cfg.items(section)
75           
76        elif isinstance(cfg, ConfigParser):
77            items = cfg.items(section)
78         
79        elif isinstance(cfg, dict):
80            items = cfg.items()     
81        else:
82            raise AttributeError('Expecting basestring, ConfigParser or dict '
83                                 'type for "cfg" attribute; got %r type' % 
84                                 type(cfg))
85       
86        prefixLen = len(prefix)
87        for optName, val in items:
88            if prefix:
89                # Filter attributes based on prefix
90                if optName.startswith(prefix):
91                    setattr(self, optName[prefixLen:], val)
92            else:
93                # No prefix set - attempt to set all attributes   
94                setattr(self, optName, val)
95               
96        if (not self.attributeQueryBinding.issuerName and 
97            self.attributeQueryBinding.sslCtxProxy.sslCertFilePath is not None):
98            issuerX509Cert = X509Cert.Read(
99                        self.attributeQueryBinding.sslCtxProxy.sslCertFilePath)
100            self.attributeQueryBinding.issuerName = str(issuerX509Cert.dn)
101           
102    def __setattr__(self, name, value):
103        """Enable setting of AttributeQuerySslSOAPBinding attributes from
104        names starting with attributeQuery.* / attributeQuery_*.  Addition for
105        setting these values from ini file
106        """
107
108        # Coerce into setting AttributeQuerySslSOAPBinding attributes -
109        # names must start with 'attributeQuery\W' e.g.
110        # attributeQuery.clockSkew or attributeQuery_issuerDN
111        if name.startswith(PIP.ATTRIBUTE_QUERY_ATTRNAME):
112            queryAttrName = name[PIP.LEN_ATTRIBUTE_QUERY_ATTRNAME+1:]
113           
114            # Skip subject related parameters to prevent settings from static
115            # configuration.  These are set at runtime
116            if queryAttrName in PIP.DISALLOWED_ATTRIBUTE_QUERY_OPTNAMES:
117                super(PIP, self).__setattr__(name, value)
118               
119            setattr(self.__attributeQueryBinding, queryAttrName, value)
120        else:
121            super(PIP, self).__setattr__(name, value)   
122
123    @property
124    def attributeQueryBinding(self):
125        """SAML SOAP Attribute Query client binding object"""
126        return self.__attributeQueryBinding
127   
128    def attributeQuery(self, attributeQuery):
129        """Query the Attribute Authority specified in the request to retrieve
130        the attributes if any corresponding to the subject
131       
132        @type attributeResponse: PIPAttributeQuery
133        @param attributeResponse:
134        @rtype: PIPAttributeResponse
135        @return: response containing the attributes retrieved from the
136        Attribute Authority"""
137        if not isinstance(attributeQuery, PIPAttributeQuery):
138            raise TypeError('Expecting %r type for input "attributeQuery"; '
139                            'got %r' % (PIPAttributeQuery, 
140                                        type(attributeQuery)))
141       
142        self.attributeQueryBinding.subjectID = attributeQuery[
143                                PIPAttributeQuery.SUBJECT_NS][Subject.USERID_NS]
144               
145        attributeAuthorityURI = attributeQuery[
146                                        PIPAttributeQuery.ATTRIBUTEAUTHORITY_NS]
147       
148        log.debug("PIP: received attribute query: %r", attributeQuery)
149         
150        try:
151            response = self.attributeQueryBinding.send(
152                                                    uri=attributeAuthorityURI)
153        finally:
154            # Ensure subject ID is reset ready for any subsequent query
155            self.attributeQueryBinding.subjectID = ''
156       
157        attributeResponse = PIPAttributeResponse()
158        attributeResponse[Subject.ROLES_NS] = []
159       
160        # Unpack assertion attribute values and add to the response object
161        for assertion in response.assertions:
162            for statement in assertion.attributeStatements:
163                for attribute in statement.attributes:
164                    attributeResponse[Subject.ROLES_NS] += [
165                        attributeValue.value
166                        for attributeValue in attribute.attributeValues
167                        if attributeValue.value not in attributeResponse[
168                                                            Subject.ROLES_NS]
169                    ]
170       
171        log.debug("PIP.attributeQuery response: %r", attributeResponse)
172       
173        return attributeResponse
Note: See TracBrowser for help on using the repository browser.