source: TI12-security/trunk/NDG_XACML/ndg/xacml/core/functions/__init__.py @ 6805

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg-security/TI12-security/trunk/NDG_XACML/ndg/xacml/core/functions/__init__.py@6805
Revision 6805, 23.4 KB checked in by pjkersha, 11 years ago (diff)

Working <Condition> statement processing. This means that policy rules can now be evaluated. The rule combining algorithm handling needs to be implemented to complete the PDP processing.

Line 
1"""NDG XACML package for functions
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "26/03/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: $"
12from abc import ABCMeta, abstractmethod
13from datetime import datetime, timedelta
14import traceback
15import logging
16log = logging.getLogger(__name__)
17
18from ndg.xacml.core.attributevalue import (AttributeValue, 
19                                           AttributeValueClassFactory)
20from ndg.xacml.utils import VettedDict, _isIterable
21from ndg.xacml.utils.factory import callModuleObject
22
23
24class AbstractFunction(object):
25    """Base class for all XACML matching functions"""
26   
27    __metaclass__ = ABCMeta
28    FUNCTION_NS = None
29    V1_0_FUNCTION_NS = "urn:oasis:names:tc:xacml:1.0:function:"
30    V2_0_FUNCTION_NS = "urn:oasis:names:tc:xacml:2.0:function:"
31   
32    def __init__(self):
33        if self.__class__.FUNCTION_NS is None:
34            raise TypeError('"FUNCTION_NS" class variable must be defined in '
35                            'derived classes')
36           
37    @abstractmethod
38    def evaluate(self, *inputs):
39        """Evaluate the function from the given input arguments and context
40        @param inputs: input arguments need to evaluate the function
41        @type inputs: tuple
42        @return: True for match, False otherwise
43        @rtype: bool
44        """
45       
46class XacmlFunctionNames(object):
47    """XACML standard match function names"""
48    FUNCTION_NAMES = (
49'urn:oasis:names:tc:xacml:1.0:function:string-equal',
50'urn:oasis:names:tc:xacml:1.0:function:boolean-equal',
51'urn:oasis:names:tc:xacml:1.0:function:integer-equal',
52'urn:oasis:names:tc:xacml:1.0:function:double-equal',
53'urn:oasis:names:tc:xacml:1.0:function:date-equal',
54'urn:oasis:names:tc:xacml:1.0:function:time-equal',
55'urn:oasis:names:tc:xacml:1.0:function:dateTime-equal',
56'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-equal',
57'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-equal',
58'urn:oasis:names:tc:xacml:1.0:function:anyURI-equal',
59'urn:oasis:names:tc:xacml:1.0:function:x500Name-equal',
60'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-equal',
61'urn:oasis:names:tc:xacml:1.0:function:hexBinary-equal',
62'urn:oasis:names:tc:xacml:1.0:function:base64Binary-equal',
63'urn:oasis:names:tc:xacml:1.0:function:integer-add',
64'urn:oasis:names:tc:xacml:1.0:function:double-add',
65'urn:oasis:names:tc:xacml:1.0:function:integer-subtract',
66'urn:oasis:names:tc:xacml:1.0:function:double-subtract',
67'urn:oasis:names:tc:xacml:1.0:function:integer-multiply',
68'urn:oasis:names:tc:xacml:1.0:function:double-multiply',
69'urn:oasis:names:tc:xacml:1.0:function:integer-divide',
70'urn:oasis:names:tc:xacml:1.0:function:double-divide',
71'urn:oasis:names:tc:xacml:1.0:function:integer-mod',
72'urn:oasis:names:tc:xacml:1.0:function:integer-abs',
73'urn:oasis:names:tc:xacml:1.0:function:double-abs',
74'urn:oasis:names:tc:xacml:1.0:function:round',
75'urn:oasis:names:tc:xacml:1.0:function:floor',
76'urn:oasis:names:tc:xacml:1.0:function:string-normalize-space',
77'urn:oasis:names:tc:xacml:1.0:function:string-normalize-to-lower-case',
78'urn:oasis:names:tc:xacml:1.0:function:double-to-integer',
79'urn:oasis:names:tc:xacml:1.0:function:integer-to-double',
80'urn:oasis:names:tc:xacml:1.0:function:or',
81'urn:oasis:names:tc:xacml:1.0:function:and',
82'urn:oasis:names:tc:xacml:1.0:function:n-of',
83'urn:oasis:names:tc:xacml:1.0:function:not',
84'urn:oasis:names:tc:xacml:1.0:function:integer-greater-than',
85'urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal',
86'urn:oasis:names:tc:xacml:1.0:function:integer-less-than',
87'urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal',
88'urn:oasis:names:tc:xacml:1.0:function:double-greater-than',
89'urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal',
90'urn:oasis:names:tc:xacml:1.0:function:double-less-than',
91'urn:oasis:names:tc:xacml:1.0:function:double-less-than-or-equal',
92'urn:oasis:names:tc:xacml:1.0:function:dateTime-add-dayTimeDuration',
93'urn:oasis:names:tc:xacml:1.0:function:dateTime-add-yearMonthDuration',
94'urn:oasis:names:tc:xacml:1.0:function:dateTime-subtract-dayTimeDuration',
95'urn:oasis:names:tc:xacml:1.0:function:dateTime-subtract-yearMonthDuration', 
96'urn:oasis:names:tc:xacml:1.0:function:date-add-yearMonthDuration',
97'urn:oasis:names:tc:xacml:1.0:function:date-subtract-yearMonthDuration',
98'urn:oasis:names:tc:xacml:1.0:function:string-greater-than',
99'urn:oasis:names:tc:xacml:1.0:function:string-greater-than-or-equal',
100'urn:oasis:names:tc:xacml:1.0:function:string-less-than',
101'urn:oasis:names:tc:xacml:1.0:function:string-less-than-or-equal',
102'urn:oasis:names:tc:xacml:1.0:function:time-greater-than',
103'urn:oasis:names:tc:xacml:1.0:function:time-greater-than-or-equal',
104'urn:oasis:names:tc:xacml:1.0:function:time-less-than',
105'urn:oasis:names:tc:xacml:1.0:function:time-less-than-or-equal',
106'urn:oasis:names:tc:xacml:2.0:function:time-in-range',
107'urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than',
108'urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than-or-equal',
109'urn:oasis:names:tc:xacml:1.0:function:dateTime-less-than',
110'urn:oasis:names:tc:xacml:1.0:function:dateTime-less-than-or-equal',
111'urn:oasis:names:tc:xacml:1.0:function:date-greater-than',
112'urn:oasis:names:tc:xacml:1.0:function:date-greater-than-or-equal',
113'urn:oasis:names:tc:xacml:1.0:function:date-less-than',
114'urn:oasis:names:tc:xacml:1.0:function:date-less-than-or-equal',
115'urn:oasis:names:tc:xacml:1.0:function:string-one-and-only',
116'urn:oasis:names:tc:xacml:1.0:function:string-bag-size',
117'urn:oasis:names:tc:xacml:1.0:function:string-is-in',
118'urn:oasis:names:tc:xacml:1.0:function:string-bag',
119'urn:oasis:names:tc:xacml:1.0:function:boolean-one-and-only',
120'urn:oasis:names:tc:xacml:1.0:function:boolean-bag-size',
121'urn:oasis:names:tc:xacml:1.0:function:boolean-is-in',
122'urn:oasis:names:tc:xacml:1.0:function:boolean-bag',
123'urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only',
124'urn:oasis:names:tc:xacml:1.0:function:integer-bag-size',
125'urn:oasis:names:tc:xacml:1.0:function:integer-is-in',
126'urn:oasis:names:tc:xacml:1.0:function:integer-bag',
127'urn:oasis:names:tc:xacml:1.0:function:double-one-and-only',
128'urn:oasis:names:tc:xacml:1.0:function:double-bag-size',
129'urn:oasis:names:tc:xacml:1.0:function:double-is-in',
130'urn:oasis:names:tc:xacml:1.0:function:double-bag',
131'urn:oasis:names:tc:xacml:1.0:function:time-one-and-only',
132'urn:oasis:names:tc:xacml:1.0:function:time-bag-size',
133'urn:oasis:names:tc:xacml:1.0:function:time-is-in',
134'urn:oasis:names:tc:xacml:1.0:function:time-bag',
135'urn:oasis:names:tc:xacml:1.0:function:date-one-and-only',
136'urn:oasis:names:tc:xacml:1.0:function:date-bag-size',
137'urn:oasis:names:tc:xacml:1.0:function:date-is-in',
138'urn:oasis:names:tc:xacml:1.0:function:date-bag',
139'urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only',
140'urn:oasis:names:tc:xacml:1.0:function:dateTime-bag-size',
141'urn:oasis:names:tc:xacml:1.0:function:dateTime-is-in',
142'urn:oasis:names:tc:xacml:1.0:function:dateTime-bag',
143'urn:oasis:names:tc:xacml:1.0:function:anyURI-one-and-only',
144'urn:oasis:names:tc:xacml:1.0:function:anyURI-bag-size',
145'urn:oasis:names:tc:xacml:1.0:function:anyURI-is-in',
146'urn:oasis:names:tc:xacml:1.0:function:anyURI-bag',
147'urn:oasis:names:tc:xacml:1.0:function:hexBinary-one-and-only',
148'urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag-size',
149'urn:oasis:names:tc:xacml:1.0:function:hexBinary-is-in',
150'urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag',
151'urn:oasis:names:tc:xacml:1.0:function:base64Binary-one-and-only',
152'urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag-size',
153'urn:oasis:names:tc:xacml:1.0:function:base64Binary-is-in',
154'urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag',
155'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-one-and-only',
156'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-bag-size',
157'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-is-in',
158'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-bag',
159'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-one-and-only',
160'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-bag-size',
161'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-is-in',
162'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-bag',
163'urn:oasis:names:tc:xacml:1.0:function:x500Name-one-and-only',
164'urn:oasis:names:tc:xacml:1.0:function:x500Name-bag-size',
165'urn:oasis:names:tc:xacml:1.0:function:x500Name-is-in',
166'urn:oasis:names:tc:xacml:1.0:function:x500Name-bag',
167'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-one-and-only',
168'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag-size',
169'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-is-in',
170'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag',
171'urn:oasis:names:tc:xacml:2.0:function:string-concatenate',
172'urn:oasis:names:tc:xacml:2.0:function:uri-string-concatenate',
173'urn:oasis:names:tc:xacml:1.0:function:any-of',
174'urn:oasis:names:tc:xacml:1.0:function:all-of',
175'urn:oasis:names:tc:xacml:1.0:function:any-of-any',
176'urn:oasis:names:tc:xacml:1.0:function:all-of-any',
177'urn:oasis:names:tc:xacml:1.0:function:any-of-all',
178'urn:oasis:names:tc:xacml:1.0:function:all-of-all',
179'urn:oasis:names:tc:xacml:1.0:function:map',
180'urn:oasis:names:tc:xacml:1.0:function:x500Name-match',
181'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-match',
182'urn:oasis:names:tc:xacml:1.0:function:string-regexp-match',
183'urn:oasis:names:tc:xacml:2.0:function:anyURI-regexp-match',
184'urn:oasis:names:tc:xacml:2.0:function:ipAddress-regexp-match',
185'urn:oasis:names:tc:xacml:2.0:function:dnsName-regexp-match',
186'urn:oasis:names:tc:xacml:2.0:function:rfc822Name-regexp-match',
187'urn:oasis:names:tc:xacml:2.0:function:x500Name-regexp-match',
188'urn:oasis:names:tc:xacml:1.0:function:xpath-node-count',
189'urn:oasis:names:tc:xacml:1.0:function:xpath-node-equal',
190'urn:oasis:names:tc:xacml:1.0:function:xpath-node-match',
191'urn:oasis:names:tc:xacml:1.0:function:string-intersection',
192'urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of',
193'urn:oasis:names:tc:xacml:1.0:function:string-union',
194'urn:oasis:names:tc:xacml:1.0:function:string-subset',
195'urn:oasis:names:tc:xacml:1.0:function:string-set-equals',
196'urn:oasis:names:tc:xacml:1.0:function:boolean-intersection',
197'urn:oasis:names:tc:xacml:1.0:function:boolean-at-least-one-member-of',
198'urn:oasis:names:tc:xacml:1.0:function:boolean-union',
199'urn:oasis:names:tc:xacml:1.0:function:boolean-subset',
200'urn:oasis:names:tc:xacml:1.0:function:boolean-set-equals',
201'urn:oasis:names:tc:xacml:1.0:function:integer-intersection',
202'urn:oasis:names:tc:xacml:1.0:function:integer-at-least-one-member-of',
203'urn:oasis:names:tc:xacml:1.0:function:integer-union',
204'urn:oasis:names:tc:xacml:1.0:function:integer-subset',
205'urn:oasis:names:tc:xacml:1.0:function:integer-set-equals',
206'urn:oasis:names:tc:xacml:1.0:function:double-intersection',
207'urn:oasis:names:tc:xacml:1.0:function:double-at-least-one-member-of',
208'urn:oasis:names:tc:xacml:1.0:function:double-union',
209'urn:oasis:names:tc:xacml:1.0:function:double-subset',
210'urn:oasis:names:tc:xacml:1.0:function:double-set-equals',
211'urn:oasis:names:tc:xacml:1.0:function:time-intersection',
212'urn:oasis:names:tc:xacml:1.0:function:time-at-least-one-member-of',
213'urn:oasis:names:tc:xacml:1.0:function:time-union',
214'urn:oasis:names:tc:xacml:1.0:function:time-subset',
215'urn:oasis:names:tc:xacml:1.0:function:time-set-equals',
216'urn:oasis:names:tc:xacml:1.0:function:date-intersection',
217'urn:oasis:names:tc:xacml:1.0:function:date-at-least-one-member-of',
218'urn:oasis:names:tc:xacml:1.0:function:date-union',
219'urn:oasis:names:tc:xacml:1.0:function:date-subset',
220'urn:oasis:names:tc:xacml:1.0:function:date-set-equals',
221'urn:oasis:names:tc:xacml:1.0:function:dateTime-intersection',
222'urn:oasis:names:tc:xacml:1.0:function:dateTime-at-least-one-member-of',
223'urn:oasis:names:tc:xacml:1.0:function:dateTime-union',
224'urn:oasis:names:tc:xacml:1.0:function:dateTime-subset',
225'urn:oasis:names:tc:xacml:1.0:function:dateTime-set-equals',
226'urn:oasis:names:tc:xacml:1.0:function:anyURI-intersection',
227'urn:oasis:names:tc:xacml:1.0:function:anyURI-at-least-one-member-of',
228'urn:oasis:names:tc:xacml:1.0:function:anyURI-union',
229'urn:oasis:names:tc:xacml:1.0:function:anyURI-subset',
230'urn:oasis:names:tc:xacml:1.0:function:anyURI-set-equals',
231'urn:oasis:names:tc:xacml:1.0:function:hexBinary-intersection',
232'urn:oasis:names:tc:xacml:1.0:function:hexBinary-at-least-one-member-of',
233'urn:oasis:names:tc:xacml:1.0:function:hexBinary-union',
234'urn:oasis:names:tc:xacml:1.0:function:hexBinary-subset',
235'urn:oasis:names:tc:xacml:1.0:function:hexBinary-set-equals',
236'urn:oasis:names:tc:xacml:1.0:function:base64Binary-intersection',
237'urn:oasis:names:tc:xacml:1.0:function:base64Binary-at-least-one-member-of',
238'urn:oasis:names:tc:xacml:1.0:function:base64Binary-union',
239'urn:oasis:names:tc:xacml:1.0:function:base64Binary-subset',
240'urn:oasis:names:tc:xacml:1.0:function:base64Binary-set-equals',
241'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-intersection',
242'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-at-least-one-member-of',
243'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-union',
244'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-subset',
245'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-set-equals',
246'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-intersection',
247'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-at-least-one-member-of',
248'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-union',
249'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-subset',
250'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-set-equals',
251'urn:oasis:names:tc:xacml:1.0:function:x500Name-intersection',
252'urn:oasis:names:tc:xacml:1.0:function:x500Name-at-least-one-member-of',
253'urn:oasis:names:tc:xacml:1.0:function:x500Name-union',
254'urn:oasis:names:tc:xacml:1.0:function:x500Name-subset',
255'urn:oasis:names:tc:xacml:1.0:function:x500Name-set-equals',
256'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-intersection',
257'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-at-least-one-member-of',
258'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-union',
259'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-subset',
260'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-set-equals',
261    )
262
263
264class FunctionClassFactoryInterface(object):
265    """Interface class for function module class factory class
266    """
267    __meta__ = ABCMeta
268   
269    @abstractmethod
270    def __call__(self, identifier):
271        '''Create class for the given XACML function identifier
272       
273        @param identifier: XACML function identifier
274        @type identifier: basestring
275        @return: at least one member of class corresponding to the given input
276        identifier
277        @rtype: AbstractFunction derived type or None if no match is
278        found
279        '''
280        return None
281   
282
283class FunctionClassFactoryBase(FunctionClassFactoryInterface):
284    """Base implementation for XACML Function Class Factory.  Derived types
285    should be implemented in sub-modules of ndg.xacml.core.functions
286   
287    e.g.
288   
289    for urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of a
290    class factory should exist,
291   
292    ndg.xacml.core.functions.v1.at_least_one_member_of.FunctionClassFactory
293   
294    which will be capable of returning an AbstractFunction derived type:
295   
296    StringAtLeastOneMemberOf   
297   
298    This class is for convenience only some function factories are better
299    derived directly from FunctionClassFactoryInterface
300   
301    Derived classes MUST define these class variables:
302   
303    @cvar FUNCTION_NAMES: list of function identifiers that this factory can
304    produce classes for e.g.:
305   
306    ('urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of', ...)
307   
308    @type FUNCTION_NAMES: NoneType (but list in derived class)
309   
310    @cvar FUNCTION_NS_SUFFIX: urn suffix for the family of function to define
311    e.g. -at-least-one-member-of is the suffix for the URN:
312   
313    urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of
314    @type FUNCTION_NS_SUFFIX: NoneType (but basestring in derived class)
315   
316    @cvar FUNCTION_BASE_CLASS: base class for this family of functions e.g for
317    urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of,
318    ndg.xacml.core.functions.v1.at_least_one_member_of.AtLeastOneMemberOfBase
319    @type FUNCTION_BASE_CLASS: NoneType (but AbstractFunction derived type in
320    derived function facotry class)
321    """
322   
323    FUNCTION_NS_SUFFIX = None
324    FUNCTION_NAMES = None
325    FUNCTION_BASE_CLASS = None
326   
327    URN_SEP = ':'
328    FUNCTION_NAME_SEP = '-'
329
330    def __init__(self):
331        """Create classes for each <type>-at-least-one-member-of function and
332        place in a look-up table
333        """
334        if None in (self.__class__.FUNCTION_NS_SUFFIX, 
335                    self.__class__.FUNCTION_BASE_CLASS):
336            raise TypeError('"FUNCTION_NS_SUFFIX" and "FUNCTION_BASE_CLASS" '
337                            'must be defined in a derived implementation of '
338                            'FunctionClassFactoryBase.  See '
339                            'FunctionClassFactoryBase.__doc__ contents')
340       
341        if not _isIterable(self.__class__.FUNCTION_NAMES):
342            raise TypeError('"FUNCTION_NAMES" class variable must be an '
343                            'iterable of string type function identifiers; got '
344                            '%r' % self.__class__.FUNCTION_NAMES)
345           
346        self.__map = {}
347        functionSuffixParts = self.__class__.FUNCTION_NS_SUFFIX.split(
348                                            self.__class__.FUNCTION_NAME_SEP)
349        functionSuffix = ''.join([n[0].upper() + n[1:] 
350                                  for n in functionSuffixParts if n])
351       
352        attributeValueClassFactory = AttributeValueClassFactory()
353       
354        for identifier in self.__class__.FUNCTION_NAMES:           
355            # Extract the function name and the type portion of the function
356            # name in order to make an implementation of a class to handle it
357            functionName = identifier.split(self.__class__.URN_SEP)[-1]
358            typePart = functionName.split(self.__class__.FUNCTION_NS_SUFFIX)[0]
359           
360            typeName = typePart[0].upper() + typePart[1:]
361            typeURI = AttributeValue.IDENTIFIER_PREFIX + typePart
362            _type = attributeValueClassFactory(typeURI)
363            if _type is None:
364                raise TypeError('No AttributeValue.TYPE_MAP entry for %r type' %
365                                typeName)
366             
367            className = typeName + functionSuffix
368            classVars = {
369                'TYPE': _type,
370                'FUNCTION_NS': identifier
371            }
372           
373            functionClass = type(className, 
374                                 (self.__class__.FUNCTION_BASE_CLASS, ), 
375                                 classVars)
376           
377            self.__map[identifier] = functionClass
378           
379    def __call__(self, identifier):
380        """Return the class for the given XACML *-at-least-one-member-of type
381        function identifier
382        @param identifier: XACML *-at-least-one-member-of type function
383        identifier
384        @type identifier: basestring
385        @return: at least one member of class corresponding to the given input
386        identifier
387        @rtype: AtLeastOneMemberOfBase derived type or None if no match is
388        found
389        """
390        return self.__map.get(identifier)
391       
392   
393class FunctionMapError(Exception):
394    """Generic Error exception class for FunctionMap"""
395   
396   
397class FunctionMapConfigError(FunctionMapError):
398    """Configuration related exception for FunctionMap"""
399       
400       
401class FunctionMap(VettedDict):
402    """Map function IDs to their implementations"""
403    FUNCTION_PKG_PREFIX = 'ndg.xacml.core.functions.'
404   
405    V1_0_PKG_PREFIX = FUNCTION_PKG_PREFIX + 'v1.'
406    V2_0_PKG_PREFIX = FUNCTION_PKG_PREFIX + 'v2.'
407   
408    SUPPORTED_NSS = {
409        AbstractFunction.V1_0_FUNCTION_NS: V1_0_PKG_PREFIX,
410        AbstractFunction.V2_0_FUNCTION_NS: V2_0_PKG_PREFIX
411    }
412   
413    # Each function module is expected to have a class factory for obtaining
414    # a class for the given function identifier associated with that module
415    FUNCTION_CLASS_FACTORY_CLASSNAME = 'FunctionClassFactory'
416   
417    def __init__(self):
418        """Force function entries to derive from AbstractFunction and IDs to
419        be string type
420        """       
421        # Filters are defined as staticmethods but reference via self here to
422        # enable derived class to override them as standard methods without
423        # needing to redefine this __init__ method           
424        super(FunctionMap, self).__init__(self.keyFilter, self.valueFilter)
425       
426    @staticmethod
427    def keyFilter(key):
428        """Enforce string type keys"""
429        if not isinstance(key, basestring):
430            raise TypeError('Expecting %r type for key; got %r' % 
431                            (basestring, type(key))) 
432           
433        return True 
434   
435    @staticmethod
436    def valueFilter(value):
437        """Enforce AbstractFunction derived types for match functions"""
438        if value is NotImplemented:
439            return True
440       
441        elif not issubclass(value, AbstractFunction):
442            raise TypeError('Expecting %r derived type for value; got %r' % 
443                            (AbstractFunction, value)) 
444           
445        return True 
446           
447    def load(self):
448        """Load function map with implementations from the relevant function
449        package"""
450       
451        for functionNs in XacmlFunctionNames.FUNCTION_NAMES:
452            self._loadFunction(functionNs)
453           
454    @classmethod
455    def withLoadedMap(cls):
456        """Return a pre-loaded map"""
457        functionMap = cls()
458        functionMap.load()
459        return functionMap
460           
461    def _loadFunction(self, functionNs):
462        """Get package to retrieve function class from for given namespace
463        """
464        cls = FunctionMap
465        classPath = None
466       
467        for namespacePrefix, pkgNamePrefix in cls.SUPPORTED_NSS.items():
468            if functionNs.startswith(namespacePrefix):
469                # Namespace is recognised - translate into a path to a function
470                # class in the right functions package
471                functionName = functionNs.split(namespacePrefix)[-1]
472                functionNameParts = functionName.split('-')
473               
474                if len(functionNameParts) == 1:
475                    moduleName = functionNameParts[0]
476                else:
477                    moduleName = '_'.join(functionNameParts[1:]).lower()
478                   
479                classPath = pkgNamePrefix + moduleName + '.' + \
480                            cls.FUNCTION_CLASS_FACTORY_CLASSNAME
481                break
482
483        if classPath is None:
484            raise FunctionMapConfigError('Namespace for function not '
485                                         'recognised: %r' % functionNs) 
486                       
487        # Try instantiating the function class and loading it into the
488        # map
489        try:
490            functionFactory = callModuleObject(classPath)
491                     
492        except (ImportError, AttributeError):
493            log.error("Error importing function factory class %r for function "
494                      "identifier %r: %s", classPath, functionNs, 
495                      traceback.format_exc())
496           
497            # No implementation exists - default to Abstract function
498            self[functionNs] = NotImplemented
499        else:
500            self[functionNs] = functionFactory(functionNs)
501           
502       
503           
504
505
506       
Note: See TracBrowser for help on using the repository browser.