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

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

Incomplete - task 2: XACML-Security Integration

  • added and and function and placeholders fro xpath-node-* functions
  • Property svn:keywords set to Id
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            if functionName == 'xpath-node-match':
359                pass
360            typePart = functionName.split(self.__class__.FUNCTION_NS_SUFFIX)[0]
361           
362            # Attempt to infer from the function name the associated type
363            typeName = typePart[0].upper() + typePart[1:]
364           
365            # Remove any hyphens converting to camel case
366            if '-' in typeName:
367                typeName = ''.join([i[0].upper() + i[1:]
368                                    for i in typeName.split('-')])
369               
370            typeURI = AttributeValue.TYPE_URI_MAP.get(typeName)
371            if typeURI is None:
372                # Ugly hack to allow for XPath node functions
373                if typePart == 'xpath-node':
374                    typeURI = AttributeValue.TYPE_URI_MAP['String']
375                else:
376                    raise TypeError('No AttributeValue.TYPE_URI_MAP entry for '
377                                    '%r type' % typePart) 
378               
379            _type = attributeValueClassFactory(typeURI)
380            if _type is None:
381                raise TypeError('No AttributeValue.TYPE_MAP entry for %r type' %
382                                typeName)
383             
384            className = typeName + functionSuffix
385            classVars = {
386                'TYPE': _type,
387                'FUNCTION_NS': identifier
388            }
389           
390            functionClass = type(className, 
391                                 (self.__class__.FUNCTION_BASE_CLASS, ), 
392                                 classVars)
393           
394            self.__map[identifier] = functionClass
395           
396    def __call__(self, identifier):
397        """Return the class for the given XACML *-at-least-one-member-of type
398        function identifier
399        @param identifier: XACML *-at-least-one-member-of type function
400        identifier
401        @type identifier: basestring
402        @return: at least one member of class corresponding to the given input
403        identifier
404        @rtype: AtLeastOneMemberOfBase derived type or None if no match is
405        found
406        """
407        return self.__map.get(identifier)
408       
409   
410class FunctionMapError(Exception):
411    """Generic Error exception class for FunctionMap"""
412   
413   
414class FunctionMapConfigError(FunctionMapError):
415    """Configuration related exception for FunctionMap"""
416       
417       
418class FunctionMap(VettedDict):
419    """Map function IDs to their implementations"""
420    FUNCTION_PKG_PREFIX = 'ndg.xacml.core.functions.'
421   
422    V1_0_PKG_PREFIX = FUNCTION_PKG_PREFIX + 'v1.'
423    V2_0_PKG_PREFIX = FUNCTION_PKG_PREFIX + 'v2.'
424   
425    SUPPORTED_NSS = {
426        AbstractFunction.V1_0_FUNCTION_NS: V1_0_PKG_PREFIX,
427        AbstractFunction.V2_0_FUNCTION_NS: V2_0_PKG_PREFIX
428    }
429   
430    # Each function module is expected to have a class factory for obtaining
431    # a class for the given function identifier associated with that module
432    FUNCTION_CLASS_FACTORY_CLASSNAME = 'FunctionClassFactory'
433   
434    def __init__(self):
435        """Force function entries to derive from AbstractFunction and IDs to
436        be string type
437        """       
438        # Filters are defined as staticmethods but reference via self here to
439        # enable derived class to override them as standard methods without
440        # needing to redefine this __init__ method           
441        super(FunctionMap, self).__init__(self.keyFilter, self.valueFilter)
442       
443    @staticmethod
444    def keyFilter(key):
445        """Enforce string type keys"""
446        if not isinstance(key, basestring):
447            raise TypeError('Expecting %r type for key; got %r' % 
448                            (basestring, type(key))) 
449           
450        return True 
451   
452    @staticmethod
453    def valueFilter(value):
454        """Enforce AbstractFunction derived types for match functions"""
455        if value is NotImplemented:
456            return True
457       
458        elif not issubclass(value, AbstractFunction):
459            raise TypeError('Expecting %r derived type for value; got %r' % 
460                            (AbstractFunction, value)) 
461           
462        return True 
463           
464    def load(self):
465        """Load function map with implementations from the relevant function
466        package"""
467       
468        for functionNs in XacmlFunctionNames.FUNCTION_NAMES:
469            self._loadFunction(functionNs)
470           
471    @classmethod
472    def withLoadedMap(cls):
473        """Return a pre-loaded map"""
474        functionMap = cls()
475        functionMap.load()
476        return functionMap
477           
478    def _loadFunction(self, functionNs):
479        """Get package to retrieve function class from for given namespace
480        """
481        cls = FunctionMap
482        classPath = None
483       
484        for namespacePrefix, pkgNamePrefix in cls.SUPPORTED_NSS.items():
485            if functionNs.startswith(namespacePrefix):
486                # Namespace is recognised - translate into a path to a function
487                # class in the right functions package
488                functionName = functionNs.split(namespacePrefix)[-1]
489                functionNameParts = functionName.split('-')
490               
491                if len(functionNameParts) == 1:
492                    moduleName = functionNameParts[0]
493                   
494                elif functionName.startswith('xpath-node'):
495                    # Ugly hack for xpath-node functions
496                    moduleName = functionNameParts[-1].lower()
497                else:
498                    moduleName = '_'.join(functionNameParts[1:]).lower()
499                   
500                classPath = pkgNamePrefix + moduleName + '.' + \
501                            cls.FUNCTION_CLASS_FACTORY_CLASSNAME
502                break
503
504        if classPath is None:
505            raise FunctionMapConfigError('Namespace for function not '
506                                         'recognised: %r' % functionNs) 
507                       
508        # Try instantiating the function class and loading it into the
509        # map
510        try:
511            functionFactory = callModuleObject(classPath)
512                     
513        except (ImportError, AttributeError):
514            log.error("Error importing function factory class %r for function "
515                      "identifier %r: %s", classPath, functionNs, 
516                      traceback.format_exc())
517           
518            # No implementation exists - default to Abstract function
519            self[functionNs] = NotImplemented
520        else:
521            self[functionNs] = functionFactory(functionNs)
522           
523       
524           
525
526
527       
Note: See TracBrowser for help on using the repository browser.