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

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

Working class factories for each function module. Function class evaluate methods need to be refactored to accept *AttributeValue? types

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