source: TI12-security/trunk/python/NDG/Gatekeeper.py @ 968

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/NDG/Gatekeeper.py@968
Revision 968, 11.2 KB checked in by pjkersha, 14 years ago (diff)

Tests/GatekeeperClientTest?.py: test Gatekeeper WS client.

Tests/AttAuthorityClientTest?.py: renamed methods so that called automatically when script is
invoked with no args.

Tests/SecurityClientTest?.py: set user to 'laurence' in order to get ACs with more roles set.

bin/LogServer.py: typo fix logs -> log

bin/GatekeeperServer.py: working version

NDG/TestGatekeeperResrc.py: test harness for Gatekeeper resource interface

NDG/gatekeeper_services_server.py: working but logic for returning matching roles needs fixing.

NDG/GatekeeperClient.py: client interface class to Gatekeeper WS.

NDG/Gatekeeper.py: working version

NDG/gatekeeper_services.py: regenerated following changes to WSDL.

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