source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/gatekeeper/gatekeeper.py @ 3079

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/gatekeeper/gatekeeper.py@3079
Revision 3079, 11.5 KB checked in by pjkersha, 13 years ago (diff)

security/python/ndg.security.common/ndg/security/common/gatekeeper: renamed Gatekeeper package -> gatekeeper.

  • Property svn:keywords set to Id
Line 
1"""NDG Gatekeeper - A PDP (Policy Decision Point) determines whether
2a given Attribute Certificate can access a given resource.
3
4NERC Data Grid Project
5"""
6__author__ = "P J Kershaw"
7__date__ = "15/05/06"
8__copyright__ = "(C) 2007 STFC & NERC"
9__contact__ = "P.J.Kershaw@rl.ac.uk"
10__license__ = \
11"""This software may be distributed under the terms of the Q Public
12License, version 1.0 or later."""
13__contact__ = "P.J.Kershaw@rl.ac.uk"
14__revision__ = "$Id$"
15
16# For parsing of properties file
17try: # python 2.5
18    from xml.etree import cElementTree as ElementTree
19except ImportError:
20    # if you've installed it yourself it comes this way
21    import cElementTree as ElementTree
22
23# Alter system path for dynamic import of resource interface class
24import sys
25
26# Expand environment vars in paths
27import os
28
29from ndg.security.common.AttCert import *
30
31
32#_____________________________________________________________________________
33class GatekeeperError(Exception):
34    """Exception handling for NDG Gatekeeper class."""
35   
36    def __init__(self, msg):
37        self.__msg = msg
38         
39    def __str__(self):
40        return self.__msg
41
42           
43#_____________________________________________________________________________
44class Gatekeeper(object):
45    """NDG Gatekeeper class - determines whether a given Attribute
46    Certificate can access a given resource."""
47   
48    __validKeys = ( 'resrcID',
49                    'resrcModFilePath',
50                    'resrcModName',
51                    'resrcClassName',
52                    'resrcPropFile',
53                    'caCertFilePath')
54   
55    #_________________________________________________________________________
56    def __init__(self, propFilePath=None, **prop):
57         
58        self.__propFilePath = propFilePath               
59        self.__resrcObj = None
60        self.__prop = {}.fromkeys(self.__validKeys)
61       
62        if propFilePath:
63            self.readProperties(propFilePath)
64           
65        # Any keywords set will override equivalent file property settings
66        if prop:
67            invalidKeys = [key for key in prop if key not in self.__validKeys]
68            if invalidKeys:
69                raise GatekeeperError("Invalid property or properties: " + \
70                                      ", ".join(invalidKeys))
71            self.__prop.update(prop)
72           
73           
74        if max(self.__prop.values()) is not None:
75            # Initialize if all required resource URI class properties are set
76            self.initResrcInterface()
77       
78       
79    #_________________________________________________________________________
80    def initResrcInterface(self):
81        """Set-up Resource URI interface to Gatekeeper"""
82       
83        try:
84            try:
85                # Temporarily extend system path ready for import
86                sysPathBak = sys.path[:]
87                sys.path.append(self.__prop['resrcModFilePath'])
88               
89                # Import module name specified in properties file
90                resrcMod = __import__(self.__prop['resrcModName'],
91                                      globals(),
92                                      locals(),
93                                      [self.__prop['resrcClassName']])
94   
95                resrcClass = eval('resrcMod.' + self.__prop['resrcClassName'])
96               
97            finally:
98                sys.path[:] = sysPathBak
99                               
100        except KeyError, e:
101            raise GatekeeperError(\
102                'Importing Resource URI module, key not recognised: %s' % e)
103                               
104        except Exception, e:
105            raise GatekeeperError('Importing Resource URI module: %s' % e)
106
107
108        # Check class inherits from GatekeeperResrc abstract base class
109        if not issubclass(resrcClass, GatekeeperResrc):
110            raise GatekeeperError, \
111                "Resource interface class %s must be derived from " % \
112                self.__prop['resrcClassName'] + "GatekeeperResrc"
113
114
115        # Instantiate custom class
116        try:
117            self.__resrcObj = resrcClass(\
118                                    resrcID=self.__prop['resrcID'],
119                                    filePath=self.__prop['resrcPropFile'])           
120        except Exception, e:
121            raise GatekeeperError(\
122                "Error instantiating Resource URI interface: " + str(e))
123
124
125    #_________________________________________________________________________
126    def readProperties(self, propFilePath=None):
127
128        """Read the configuration properties for the Attribute Authority
129
130        propFilePath: file path to properties file
131        """
132       
133        if propFilePath is not None:
134            if not isinstance(propFilePath, basestring):
135                raise GatekeeperError("Input Properties file path " + \
136                                        "must be a valid string.")
137           
138            self.__propFilePath = propFilePath
139
140
141        try:
142            elems = ElementTree.parse(self.__propFilePath).getroot()
143           
144        except IOError, ioErr:
145            raise GatekeeperError(\
146                                "Error parsing properties file \"%s\": %s" % \
147                                (ioErr.filename, ioErr.strerror))
148                               
149        # Copy properties from file as dictionary
150        #
151        # Nb. # Allow for environment variables in paths
152        self.__prop.update(dict([(elem.tag, 
153                                  os.path.expandvars(elem.text.strip())) \
154                                 for elem in elems if elem.text is not None]))
155
156
157        # Check for missing properties
158        propKeys = self.__prop.keys()
159        missingKeys = [key for key in Gatekeeper.__validKeys \
160                       if key not in propKeys]
161        if missingKeys != []:
162            raise GatekeeperError("The following properties are " + \
163                                  "missing from the properties file: " + \
164                                  ', '.join(missingKeys))
165
166
167    def __formatInput(self, input):
168        """Convert generic input into a list of roles - use with access
169        routines"""
170       
171        if isinstance(input, list):
172            # Input is list of roles
173            return input
174             
175        elif isinstance(input, basestring):
176            # Input is a role
177            return [input]
178           
179        elif isinstance(input, AttCert):
180            # Input is an Attribute Certificate
181            # Check signature of AttCert
182            try:
183                input.isValid(raiseExcep=True, 
184                              certFilePathList=self.__prop['caCertFilePath'])
185            except Exception, e:
186                raise GatekeeperError, "Access denied for input: %s" % str(e)
187           
188            return input.roles
189        else:
190            raise GatekeeperError("Input must be a role, role list or " + \
191                                  "Attribute Certificate type")
192
193   
194    #_________________________________________________________________________
195    def __call__(self, input):
196        """Get the permissions for the input file, list of roles or
197        Attribute Certificate containing roles.  A Dictionary of permissions
198        are returned indexed by role name.  Permissions are expressed as a
199        tuple containing the relevant permissions flags e.g. ('r', 'w', 'x')
200        for read/write/execute permission or e.g. ('x') for exceute only
201        permission"""
202       
203        roleList = self.__formatInput(input)
204                                     
205        return dict([(role, self.__resrcObj.getPermissions(role)) \
206                     for role in roleList])
207       
208   
209    getPermissions = __call__
210   
211   
212    #_________________________________________________________________________
213    def readAccess(self, input):
214        """Determine read access permitted against the given
215        input role/role list or Attribute Certificate roles
216       
217        Return a dictionary of booleans for access granted/denied keyed
218        by role name"""
219       
220        roleList = self.__formatInput(input)
221       
222        return dict([(role, self.__resrcObj.readAccess(role)) \
223                     for role in roleList])
224   
225   
226    #_________________________________________________________________________
227    def writeAccess(self, input):
228        """Determine write access permitted against the given
229        input role/role list or Attribute Certificate roles
230       
231        Return a dictionary of booleans for access granted/denied keyed
232        by role name"""
233       
234        roleList = self.__formatInput(input)
235       
236        return dict([(role, self.__resrcObj.writeAccess(role)) \
237                     for role in roleList])
238   
239   
240    #_________________________________________________________________________
241    def executeAccess(self, input):
242        """Determine execute access permitted against the given
243        input role/role list or Attribute Certificate roles
244       
245        Return a dictionary of booleans for access granted/denied keyed
246        by role name"""
247       
248        roleList = self.__formatInput(input)
249       
250        return dict([(role, self.__resrcObj.executeAccess(role)) \
251                     for role in roleList])
252                     
253
254#_____________________________________________________________________________
255class GatekeeperResrcError(GatekeeperError):
256    """Exception handling for NDG Gatekeeper Resource interface class
257    class."""
258    pass
259
260
261#_____________________________________________________________________________
262class GatekeeperResrc:
263    """An abstract base class to define the resource -> role interface
264    for the Gatekeeper.
265
266    Each NDG resource should implement a derived class which implements
267    the way a resource roles is served from the given resource."""
268
269    # User defined class may wish to specify a URI or path for a configuration
270    # file
271    def __init__(self, resrcID=None, filePath=None):
272        """Abstract base class - derive from this class to define
273        resource role interface to Gatekeeper"""
274        raise NotImplementedError(\
275            self.__init__.__doc__.replace('\n       ',''))
276   
277
278    def getPermissions(self, role):
279        """Derived method should return the permissions for the given resource
280        role.  Format is a tuple e.g.
281           
282        ('r', 'w', 'x'): read, write and execute permission granted for this
283                         role
284        ():              access denied
285        ('r',):          read only access
286        ('r', 'x'):      read and execute permission granted
287       
288        This method is needed for the interface to the Gatekeeper class"""
289        raise NotImplementedError(
290            self.__getPermissions.__doc__.replace('\n       ',''))
291
292
293    def readAccess(self, role):
294        """Derived method should return the role for read access to the
295        resource - should return boolean for access granted/denied"""
296        raise NotImplementedError(
297            self.readAccess.__doc__.replace('\n       ',''))
298
299
300    def writeAccess(self, role):
301        """Derived method should return the role for write access to the
302        resource - should return boolean for access granted/denied"""
303        raise NotImplementedError(
304            self.writeAccess.__doc__.replace('\n       ',''))
305
306
307    def executeAccess(self, role):
308        """Derived method should return the role for execute access to the
309        resource - should return boolean for access granted/denied"""
310        raise NotImplementedError(
311            self.executeAccess.__doc__.replace('\n       ',''))
312   
313           
Note: See TracBrowser for help on using the repository browser.