source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/pep.py @ 4840

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/pep.py@5162
Revision 4840, 8.0 KB checked in by pjkersha, 12 years ago (diff)

Fix problem with search and replace licence not adding a new line.

Line 
1"""NDG Gatekeeper - A PEP (Policy Enforcement Point) enforces authorisation
2decision made by a PDP (Policy Decision Point)
3
4Adapted from original gatekeeper.py code
5
6NERC Data Grid Project
7"""
8__author__ = "P J Kershaw"
9__date__ = "04/04/08"
10__copyright__ = "(C) 2009 Science and Technology Facilities Council"
11__contact__ = "Philip.Kershaw@stfc.ac.uk"
12__license__ = "BSD - see LICENSE file in top-level directory"
13__contact__ = "Philip.Kershaw@stfc.ac.uk"
14__revision__ = "$Id$"
15
16import logging
17log = logging.getLogger(__name__)
18
19# For parsing of properties file
20from os.path import expandvars as expVars
21
22# Expand environment vars in paths
23import os
24
25# System path modification for module import
26import sys
27
28from ConfigParser import SafeConfigParser
29from ndg.security.common.AttCert import *
30from ndg.security.common.authz.pdp import PDPInterface
31
32class PEPError(Exception):
33    """Exception handling for NDG Policy Enforcement Point class."""
34
35class PDPInitError(PEPError):
36    """Errors importing and instantiating Policy Decision Point class"""
37
38           
39class PEP(object):
40    """NDG Policy Enforcement Point class - determines whether a given
41    Attribute Certificate can access a given resource."""
42   
43    defParam = {'pdpModFilePath': None,
44                'pdpModName': '<pdpModName>',
45                'pdpClassName': '<pdpClassName>',
46                'pdpCfgFilePath': None,
47                'pdpCfgSection': 'DEFAULT'}
48   
49    def __init__(self,
50                 cfg=None,
51                 cfgSection='DEFAULT',
52                 pdpCfgKw={},
53                 **prop):
54        '''Initialise settings from a config file and/or keyword settings
55       
56        @type cfg: string / ConfigParser object
57        @param cfg: if a string type, this is interpreted as the file path to
58        a configuration file, otherwise it will be treated as a ConfigParser
59        object
60        @type cfgSection: string
61        @param cfgSection: sets the section name to retrieve config params
62        from
63        @type pdpCfgKw: dict
64        @param pdpCfgKw: parameters to pass to PDP interface - alternative to
65        passing settings in a config file or config object.  Keywords override
66        any duplicates set by the latter.
67        @type prop: dict
68        @param prop: set parameters as key value pairs.'''
69         
70        log.debug("PEP.__init__ ...")
71        self._pdp = None
72        self._pdpCfgKw = pdpCfgKw
73       
74        if isinstance(cfg, basestring):
75            log.debug('Setting PEP config from file: "%s" ...' % cfg)
76            self._cfg = SafeConfigParser()
77            self.readConfig(cfg)
78        else:
79            log.debug('Setting PEP config from existing config object ...')
80            self._cfg = cfg
81           
82        if cfg: # i.e. at least some kind of config was input
83            self.parseConfig(cfgSection)
84           
85        # Any keywords set will override equivalent file property settings
86        # Copy directly into attribute of this object
87        for paramName in prop:
88            if paramName not in PEP.defParam:
89                raise AttributeError(
90                            'Keyword "%s" is not a valid config parameter' % \
91                            paramName)
92            setattr(self, paramName, expVars(prop['paramName']))
93
94        # Default parameters if not set above
95        for paramName in PEP.defParam:
96            if not hasattr(self, paramName):
97                setattr(self, paramName, PEP.defParam[paramName])
98       
99        if not hasattr(self, 'pdpCfgSection'):
100            self.pdpCfgSection = 'DEFAULT'
101           
102        # Check for minimum param settings necessary for initialising a PDP
103        # object (the module can be on the existing class path)
104        if getattr(self, 'pdpModName', None) and \
105           getattr(self, 'pdpClassName', None):
106            # Initialize if all required resource URI class properties are set
107            self.initPDPInterface()
108       
109       
110    def initPDPInterface(self):
111        """Set-up PDP interface to PEP"""
112       
113        log.debug("PEP.initPDPInterface ...")
114        sysPathBak = None # extra bullet proofing for finally block
115        try:
116            try:
117                # Temporarily extend system path ready for import
118                if self.pdpModFilePath:
119                    sysPathBak = sys.path[:]
120                    sys.path.append(self.pdpModFilePath)
121
122                # Import module name specified in properties file
123                pdpMod = __import__(self.pdpModName,
124                                    globals(),
125                                    locals(),
126                                    [self.pdpClassName])
127   
128                pdpClass = eval('pdpMod.' + self.pdpClassName)
129
130            finally:
131                if sysPathBak:
132                    sys.path[:] = sysPathBak
133                               
134        except KeyError, e:
135            raise PDPInitError('Importing PDP module, key not recognised: %s' %
136                               e)                         
137        except Exception, e:
138            raise PDPInitError('Importing PDP module: %s' % e)
139
140
141        # Check class inherits from PEPResrc abstract base class
142        if not issubclass(pdpClass, PDPInterface):
143            raise PDPInitError("PDP interface class %s must be derived from "
144                               "PDPInterface" % self.pdpClassName)
145
146
147        # Instantiate custom class
148        self._pdp = pdpClass(cfg=self.pdpCfgFilePath or self._cfg,
149                             cfgSection=self.pdpCfgSection,
150                             **self._pdpCfgKw)           
151
152
153    def readConfig(self, cfgFilePath):
154        """Read the configuration file"""
155        self._cfg.read(cfgFilePath)
156
157
158    def parseConfig(self, section='DEFAULT'):
159        '''Extract config properties for the interface to the PDP'''
160       
161        log.debug("PEP.parseConfig ...")
162       
163        # Copy directly into attribute of this object
164        for paramName in PEP.defParam:
165            if self._cfg.has_option(section, paramName): 
166                val = expVars(self._cfg.get(section, paramName, None))
167                setattr(self, paramName, val)
168            else:
169                setattr(self, paramName, PEP.defParam[paramName])
170
171   
172    def __call__(self, resrcHandle, userHandle, accessType, *arg, **kw):
173        """Make an Access control decision with this behaviour:
174       
175        @type resrcHandle: any - determined by the PDP used
176        @param resrcHandle: a handle to the resource which the PEP protects. 
177        This could be for example a resource ID string, or a dict or other
178        object to hold resource information required by the PDP
179       
180        @type userHandle: any - determined by the PDP used
181        @param userHandle: a handle to the user requesting access. 
182        e.g. a user ID, an attribute certificate or a handle to a service
183        which can be interrogated to get the required information
184       
185        @type accessType: any - determined by the PDP used
186        @param accessType: the type of access being requested e.g. read,
187        read/write, put etc.
188       
189        @rtype: bool
190        @return: True if access permitted; False if denied or else raise
191        an Exception
192       
193        Nb.
194       
195        *arg and **kw are included to enable further customisation,
196        resrcHandle, userHandle and accessType are merely indicators.
197       
198        The alias to this method 'accessPermitted'"""
199       
200        if self._pdp is None:
201            raise PDPInitError("PDP object is not set - ensure "
202                               "initPDPInterface has been called and the "
203                               "relevant configuration parameters have been "
204                               "set")
205           
206        return self._pdp.accessPermitted(resrcHandle, 
207                                         userHandle, 
208                                         accessType, 
209                                         *arg, 
210                                         **kw)
211       
212    accessPermitted = __call__
213   
214   
215def accessPermitted():
216    '''Convenience wrapper routine for PEP'''
Note: See TracBrowser for help on using the repository browser.