1 """NDG XACML package for functions
2
3 NERC DataGrid
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: __init__.py 8045 2012-03-16 17:50:04Z rwilkinson $"
12 from abc import ABCMeta, abstractmethod
13 from datetime import datetime, timedelta
14 import traceback
15 import logging
16 log = logging.getLogger(__name__)
17
18 from ndg.xacml.core.attributevalue import (AttributeValue,
19 AttributeValueClassFactory)
20 from ndg.xacml.utils import VettedDict, _isIterable
21 from ndg.xacml.utils.factory import callModuleObject
22
23
24
25
26 SPECIAL_TYPE_MAP = {
27 'url-string': 'AnyURI',
28 'xpath-node': 'String'}
31 """Abstract Base class for all XACML matching functions
32 @cvar FUNCTION_NS: namespace for the given function
33 @type FUNCTION_NS: NoneType (must be string in derived type)
34
35 @cvar V1_0_FUNCTION_NS: XACML 1.0 function namespace prefix
36 @type V1_0_FUNCTION_NS: string
37
38 @cvar V2_0_FUNCTION_NS: XACML 2.0 function namespace prefix
39 @type V2_0_FUNCTION_NS: string
40 """
41 __metaclass__ = ABCMeta
42
43 FUNCTION_NS = None
44 V1_0_FUNCTION_NS = "urn:oasis:names:tc:xacml:1.0:function:"
45 V2_0_FUNCTION_NS = "urn:oasis:names:tc:xacml:2.0:function:"
46
48 """
49 @raise TypeError: if FUNCTION_NS not set correctly
50 """
51 if self.__class__.FUNCTION_NS is None:
52 raise TypeError('"FUNCTION_NS" class variable must be defined in '
53 'derived classes')
54
55 @abstractmethod
57 """Evaluate the function from the given input arguments and context
58
59 @param inputs: input arguments need to evaluate the function
60 @type inputs: tuple
61 @return: derived type should return True for match, False otherwise
62 @rtype: bool (derived type), NoneType for THIS implementation
63 """
64
67 """XACML standard match function names
68
69 @cvar FUNCTION_NAMES: list of all the XACML function URNs
70 @type FUNCTION_NAMES: tuple
71 """
72 FUNCTION_NAMES = (
73 'urn:oasis:names:tc:xacml:1.0:function:string-equal',
74 'urn:oasis:names:tc:xacml:1.0:function:boolean-equal',
75 'urn:oasis:names:tc:xacml:1.0:function:integer-equal',
76 'urn:oasis:names:tc:xacml:1.0:function:double-equal',
77 'urn:oasis:names:tc:xacml:1.0:function:date-equal',
78 'urn:oasis:names:tc:xacml:1.0:function:time-equal',
79 'urn:oasis:names:tc:xacml:1.0:function:dateTime-equal',
80 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-equal',
81 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-equal',
82 'urn:oasis:names:tc:xacml:1.0:function:anyURI-equal',
83 'urn:oasis:names:tc:xacml:1.0:function:x500Name-equal',
84 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-equal',
85 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-equal',
86 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-equal',
87 'urn:oasis:names:tc:xacml:1.0:function:integer-add',
88 'urn:oasis:names:tc:xacml:1.0:function:double-add',
89 'urn:oasis:names:tc:xacml:1.0:function:integer-subtract',
90 'urn:oasis:names:tc:xacml:1.0:function:double-subtract',
91 'urn:oasis:names:tc:xacml:1.0:function:integer-multiply',
92 'urn:oasis:names:tc:xacml:1.0:function:double-multiply',
93 'urn:oasis:names:tc:xacml:1.0:function:integer-divide',
94 'urn:oasis:names:tc:xacml:1.0:function:double-divide',
95 'urn:oasis:names:tc:xacml:1.0:function:integer-mod',
96 'urn:oasis:names:tc:xacml:1.0:function:integer-abs',
97 'urn:oasis:names:tc:xacml:1.0:function:double-abs',
98 'urn:oasis:names:tc:xacml:1.0:function:round',
99 'urn:oasis:names:tc:xacml:1.0:function:floor',
100 'urn:oasis:names:tc:xacml:1.0:function:string-normalize-space',
101 'urn:oasis:names:tc:xacml:1.0:function:string-normalize-to-lower-case',
102 'urn:oasis:names:tc:xacml:1.0:function:double-to-integer',
103 'urn:oasis:names:tc:xacml:1.0:function:integer-to-double',
104 'urn:oasis:names:tc:xacml:1.0:function:or',
105 'urn:oasis:names:tc:xacml:1.0:function:and',
106 'urn:oasis:names:tc:xacml:1.0:function:n-of',
107 'urn:oasis:names:tc:xacml:1.0:function:not',
108 'urn:oasis:names:tc:xacml:1.0:function:integer-greater-than',
109 'urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal',
110 'urn:oasis:names:tc:xacml:1.0:function:integer-less-than',
111 'urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal',
112 'urn:oasis:names:tc:xacml:1.0:function:double-greater-than',
113 'urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal',
114 'urn:oasis:names:tc:xacml:1.0:function:double-less-than',
115 'urn:oasis:names:tc:xacml:1.0:function:double-less-than-or-equal',
116 'urn:oasis:names:tc:xacml:1.0:function:dateTime-add-dayTimeDuration',
117 'urn:oasis:names:tc:xacml:1.0:function:dateTime-add-yearMonthDuration',
118 'urn:oasis:names:tc:xacml:1.0:function:dateTime-subtract-dayTimeDuration',
119 'urn:oasis:names:tc:xacml:1.0:function:dateTime-subtract-yearMonthDuration',
120 'urn:oasis:names:tc:xacml:1.0:function:date-add-yearMonthDuration',
121 'urn:oasis:names:tc:xacml:1.0:function:date-subtract-yearMonthDuration',
122 'urn:oasis:names:tc:xacml:1.0:function:string-greater-than',
123 'urn:oasis:names:tc:xacml:1.0:function:string-greater-than-or-equal',
124 'urn:oasis:names:tc:xacml:1.0:function:string-less-than',
125 'urn:oasis:names:tc:xacml:1.0:function:string-less-than-or-equal',
126 'urn:oasis:names:tc:xacml:1.0:function:time-greater-than',
127 'urn:oasis:names:tc:xacml:1.0:function:time-greater-than-or-equal',
128 'urn:oasis:names:tc:xacml:1.0:function:time-less-than',
129 'urn:oasis:names:tc:xacml:1.0:function:time-less-than-or-equal',
130 'urn:oasis:names:tc:xacml:2.0:function:time-in-range',
131 'urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than',
132 'urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than-or-equal',
133 'urn:oasis:names:tc:xacml:1.0:function:dateTime-less-than',
134 'urn:oasis:names:tc:xacml:1.0:function:dateTime-less-than-or-equal',
135 'urn:oasis:names:tc:xacml:1.0:function:date-greater-than',
136 'urn:oasis:names:tc:xacml:1.0:function:date-greater-than-or-equal',
137 'urn:oasis:names:tc:xacml:1.0:function:date-less-than',
138 'urn:oasis:names:tc:xacml:1.0:function:date-less-than-or-equal',
139 'urn:oasis:names:tc:xacml:1.0:function:string-one-and-only',
140 'urn:oasis:names:tc:xacml:1.0:function:string-bag-size',
141 'urn:oasis:names:tc:xacml:1.0:function:string-is-in',
142 'urn:oasis:names:tc:xacml:1.0:function:string-bag',
143 'urn:oasis:names:tc:xacml:1.0:function:boolean-one-and-only',
144 'urn:oasis:names:tc:xacml:1.0:function:boolean-bag-size',
145 'urn:oasis:names:tc:xacml:1.0:function:boolean-is-in',
146 'urn:oasis:names:tc:xacml:1.0:function:boolean-bag',
147 'urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only',
148 'urn:oasis:names:tc:xacml:1.0:function:integer-bag-size',
149 'urn:oasis:names:tc:xacml:1.0:function:integer-is-in',
150 'urn:oasis:names:tc:xacml:1.0:function:integer-bag',
151 'urn:oasis:names:tc:xacml:1.0:function:double-one-and-only',
152 'urn:oasis:names:tc:xacml:1.0:function:double-bag-size',
153 'urn:oasis:names:tc:xacml:1.0:function:double-is-in',
154 'urn:oasis:names:tc:xacml:1.0:function:double-bag',
155 'urn:oasis:names:tc:xacml:1.0:function:time-one-and-only',
156 'urn:oasis:names:tc:xacml:1.0:function:time-bag-size',
157 'urn:oasis:names:tc:xacml:1.0:function:time-is-in',
158 'urn:oasis:names:tc:xacml:1.0:function:time-bag',
159 'urn:oasis:names:tc:xacml:1.0:function:date-one-and-only',
160 'urn:oasis:names:tc:xacml:1.0:function:date-bag-size',
161 'urn:oasis:names:tc:xacml:1.0:function:date-is-in',
162 'urn:oasis:names:tc:xacml:1.0:function:date-bag',
163 'urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only',
164 'urn:oasis:names:tc:xacml:1.0:function:dateTime-bag-size',
165 'urn:oasis:names:tc:xacml:1.0:function:dateTime-is-in',
166 'urn:oasis:names:tc:xacml:1.0:function:dateTime-bag',
167 'urn:oasis:names:tc:xacml:1.0:function:anyURI-one-and-only',
168 'urn:oasis:names:tc:xacml:1.0:function:anyURI-bag-size',
169 'urn:oasis:names:tc:xacml:1.0:function:anyURI-is-in',
170 'urn:oasis:names:tc:xacml:1.0:function:anyURI-bag',
171 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-one-and-only',
172 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag-size',
173 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-is-in',
174 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag',
175 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-one-and-only',
176 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag-size',
177 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-is-in',
178 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag',
179 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-one-and-only',
180 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-bag-size',
181 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-is-in',
182 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-bag',
183 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-one-and-only',
184 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-bag-size',
185 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-is-in',
186 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-bag',
187 'urn:oasis:names:tc:xacml:1.0:function:x500Name-one-and-only',
188 'urn:oasis:names:tc:xacml:1.0:function:x500Name-bag-size',
189 'urn:oasis:names:tc:xacml:1.0:function:x500Name-is-in',
190 'urn:oasis:names:tc:xacml:1.0:function:x500Name-bag',
191 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-one-and-only',
192 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag-size',
193 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-is-in',
194 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag',
195 'urn:oasis:names:tc:xacml:2.0:function:string-concatenate',
196 'urn:oasis:names:tc:xacml:2.0:function:uri-string-concatenate',
197 'urn:oasis:names:tc:xacml:1.0:function:any-of',
198 'urn:oasis:names:tc:xacml:1.0:function:all-of',
199 'urn:oasis:names:tc:xacml:1.0:function:any-of-any',
200 'urn:oasis:names:tc:xacml:1.0:function:all-of-any',
201 'urn:oasis:names:tc:xacml:1.0:function:any-of-all',
202 'urn:oasis:names:tc:xacml:1.0:function:all-of-all',
203 'urn:oasis:names:tc:xacml:1.0:function:map',
204 'urn:oasis:names:tc:xacml:1.0:function:x500Name-match',
205 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-match',
206 'urn:oasis:names:tc:xacml:1.0:function:string-regexp-match',
207 'urn:oasis:names:tc:xacml:2.0:function:anyURI-regexp-match',
208 'urn:oasis:names:tc:xacml:2.0:function:ipAddress-regexp-match',
209 'urn:oasis:names:tc:xacml:2.0:function:dnsName-regexp-match',
210 'urn:oasis:names:tc:xacml:2.0:function:rfc822Name-regexp-match',
211 'urn:oasis:names:tc:xacml:2.0:function:x500Name-regexp-match',
212 'urn:oasis:names:tc:xacml:1.0:function:xpath-node-count',
213 'urn:oasis:names:tc:xacml:1.0:function:xpath-node-equal',
214 'urn:oasis:names:tc:xacml:1.0:function:xpath-node-match',
215 'urn:oasis:names:tc:xacml:1.0:function:string-intersection',
216 'urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of',
217 'urn:oasis:names:tc:xacml:1.0:function:string-union',
218 'urn:oasis:names:tc:xacml:1.0:function:string-subset',
219 'urn:oasis:names:tc:xacml:1.0:function:string-set-equals',
220 'urn:oasis:names:tc:xacml:1.0:function:boolean-intersection',
221 'urn:oasis:names:tc:xacml:1.0:function:boolean-at-least-one-member-of',
222 'urn:oasis:names:tc:xacml:1.0:function:boolean-union',
223 'urn:oasis:names:tc:xacml:1.0:function:boolean-subset',
224 'urn:oasis:names:tc:xacml:1.0:function:boolean-set-equals',
225 'urn:oasis:names:tc:xacml:1.0:function:integer-intersection',
226 'urn:oasis:names:tc:xacml:1.0:function:integer-at-least-one-member-of',
227 'urn:oasis:names:tc:xacml:1.0:function:integer-union',
228 'urn:oasis:names:tc:xacml:1.0:function:integer-subset',
229 'urn:oasis:names:tc:xacml:1.0:function:integer-set-equals',
230 'urn:oasis:names:tc:xacml:1.0:function:double-intersection',
231 'urn:oasis:names:tc:xacml:1.0:function:double-at-least-one-member-of',
232 'urn:oasis:names:tc:xacml:1.0:function:double-union',
233 'urn:oasis:names:tc:xacml:1.0:function:double-subset',
234 'urn:oasis:names:tc:xacml:1.0:function:double-set-equals',
235 'urn:oasis:names:tc:xacml:1.0:function:time-intersection',
236 'urn:oasis:names:tc:xacml:1.0:function:time-at-least-one-member-of',
237 'urn:oasis:names:tc:xacml:1.0:function:time-union',
238 'urn:oasis:names:tc:xacml:1.0:function:time-subset',
239 'urn:oasis:names:tc:xacml:1.0:function:time-set-equals',
240 'urn:oasis:names:tc:xacml:1.0:function:date-intersection',
241 'urn:oasis:names:tc:xacml:1.0:function:date-at-least-one-member-of',
242 'urn:oasis:names:tc:xacml:1.0:function:date-union',
243 'urn:oasis:names:tc:xacml:1.0:function:date-subset',
244 'urn:oasis:names:tc:xacml:1.0:function:date-set-equals',
245 'urn:oasis:names:tc:xacml:1.0:function:dateTime-intersection',
246 'urn:oasis:names:tc:xacml:1.0:function:dateTime-at-least-one-member-of',
247 'urn:oasis:names:tc:xacml:1.0:function:dateTime-union',
248 'urn:oasis:names:tc:xacml:1.0:function:dateTime-subset',
249 'urn:oasis:names:tc:xacml:1.0:function:dateTime-set-equals',
250 'urn:oasis:names:tc:xacml:1.0:function:anyURI-intersection',
251 'urn:oasis:names:tc:xacml:1.0:function:anyURI-at-least-one-member-of',
252 'urn:oasis:names:tc:xacml:1.0:function:anyURI-union',
253 'urn:oasis:names:tc:xacml:1.0:function:anyURI-subset',
254 'urn:oasis:names:tc:xacml:1.0:function:anyURI-set-equals',
255 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-intersection',
256 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-at-least-one-member-of',
257 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-union',
258 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-subset',
259 'urn:oasis:names:tc:xacml:1.0:function:hexBinary-set-equals',
260 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-intersection',
261 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-at-least-one-member-of',
262 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-union',
263 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-subset',
264 'urn:oasis:names:tc:xacml:1.0:function:base64Binary-set-equals',
265 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-intersection',
266 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-at-least-one-member-of',
267 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-union',
268 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-subset',
269 'urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-set-equals',
270 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-intersection',
271 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-at-least-one-member-of',
272 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-union',
273 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-subset',
274 'urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-set-equals',
275 'urn:oasis:names:tc:xacml:1.0:function:x500Name-intersection',
276 'urn:oasis:names:tc:xacml:1.0:function:x500Name-at-least-one-member-of',
277 'urn:oasis:names:tc:xacml:1.0:function:x500Name-union',
278 'urn:oasis:names:tc:xacml:1.0:function:x500Name-subset',
279 'urn:oasis:names:tc:xacml:1.0:function:x500Name-set-equals',
280 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-intersection',
281 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-at-least-one-member-of',
282 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-union',
283 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-subset',
284 'urn:oasis:names:tc:xacml:1.0:function:rfc822Name-set-equals',
285 )
286
287 from ndg.xacml import XacmlError
291 """Encountered a function type that is not recognised as part of the XACML
292 specification and is not supported in this implementation"""
293
296 """Encountered a function type that is not supported even though it is
297 part of the XACML specification"""
298
301 """Factory function to return an unsupported function exception based on
302 the function identifier passed in
303
304 @param identifier: XACML function namespace to check
305 @type identifier: basestring
306
307 @return: unsupported function exception instance
308 @rtype: UnsupportedFunctionError or UnsupportedStdFunctionError depending
309 on the identifier passed
310 """
311 if identifier in XacmlFunctionNames.FUNCTION_NAMES:
312 if msg is None:
313 msg = "%s: %s" % (UnsupportedStdFunctionError.__doc__, identifier)
314
315 raise UnsupportedStdFunctionError(msg)
316 else:
317 if msg is None:
318 msg = "%s: %s" % (UnsupportedFunctionError.__doc__, identifier)
319
320 raise UnsupportedFunctionError(msg)
321
324 """Attempting to overwrite a standard function namespace with a custom one
325 (probably from load_custom_function method)"""
326
329 """Interface class for function module class factory class
330 """
331 __meta__ = ABCMeta
332
333 @abstractmethod
335 '''Create class for the given XACML function identifier
336
337 @param identifier: XACML function identifier
338 @type identifier: basestring
339 @return: at least one member of class corresponding to the given input
340 identifier
341 @rtype: AbstractFunction derived type or NoneType if no match is found
342 '''
343 return None
344
347 """Base implementation for XACML Function Class Factory. There should be
348 one derived type for each function family implemented in sub-modules of
349 ndg.xacml.core.functions
350
351 e.g.
352
353 for urn:oasis:names:tc:xacml:1.0:function:<type>-at-least-one-member-of a
354 class factory should exist,
355
356 ndg.xacml.core.functions.v1.at_least_one_member_of.FunctionClassFactory
357
358 which will be capable of returning a type derived from AbstractFunction:
359
360 <type>AtLeastOneMemberOf
361
362 e.g. StringAtLeastOneMemberOf, BooleanAtLeastOneMemberOf.
363
364 This class is for convenience only some function factories are better
365 derived directly from FunctionClassFactoryInterface
366
367 Derived classes MUST define these class variables:
368
369 @cvar FUNCTION_NAMES: list of function identifiers that this factory can
370 produce classes for e.g.:
371
372 ('urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of', ...)
373
374 @type FUNCTION_NAMES: NoneType (but list in derived class)
375
376 @cvar FUNCTION_NS_SUFFIX: urn suffix for the family of function to define
377 e.g. -at-least-one-member-of is the suffix for the URN:
378
379 urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of
380 @type FUNCTION_NS_SUFFIX: NoneType (but basestring in derived class)
381
382 @cvar FUNCTION_BASE_CLASS: base class for this family of functions e.g for
383 urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of,
384 ndg.xacml.core.functions.v1.at_least_one_member_of.AtLeastOneMemberOfBase
385 @type FUNCTION_BASE_CLASS: NoneType (but AbstractFunction derived type in
386 derived function factory class)
387 """
388
389 FUNCTION_NS_SUFFIX = None
390 FUNCTION_NAMES = None
391 FUNCTION_BASE_CLASS = None
392
393 URN_SEP = ':'
394 FUNCTION_NAME_SEP = '-'
395 __slots__ = ('__map', 'attributeValueClassFactory', 'functionSuffix')
396
398 '''This class is in fact abstract - derived types must define the
399 FUNCTION_NS_SUFFIX and FUNCTION_BASE_CLASS class variables
400 '''
401 if None in (self.__class__.FUNCTION_NS_SUFFIX,
402 self.__class__.FUNCTION_BASE_CLASS):
403 raise TypeError('"FUNCTION_NS_SUFFIX" and "FUNCTION_BASE_CLASS" '
404 'must be defined in a derived implementation of '
405 'FunctionClassFactoryBase. See '
406 'FunctionClassFactoryBase.__doc__ contents')
407
408 if not _isIterable(self.__class__.FUNCTION_NAMES):
409 raise TypeError('"FUNCTION_NAMES" class variable must be an '
410 'iterable of string type function identifiers; got '
411 '%r' % self.__class__.FUNCTION_NAMES)
412
413 self.__map = {}
414
415
416
417 self.attributeValueClassFactory = AttributeValueClassFactory()
418
419
420 functionSuffixParts = self.__class__.FUNCTION_NS_SUFFIX.split(
421 self.__class__.FUNCTION_NAME_SEP)
422 self.functionSuffix = ''.join([n[0].upper() + n[1:]
423 for n in functionSuffixParts if n])
424
426 """Create classes for all functions for a data type e.g. a derived class
427 could implement a factory for <type>-at-least-one-member-of functions:
428 string-at-least-one-member-of, boolean-at-least-one-member-of, etc.
429
430 Function classes are placed in a look-up table __map for the __call__()
431 method to access
432
433 In practice, there shouldn't be a need to load all the functions in
434 one go. The __call__ method loads functions and caches them as needed.
435 """
436 for identifier in self.__class__.FUNCTION_NAMES:
437 self.loadFunction(identifier)
438
440 """Create a class for the given function namespace and cache it in the
441 function class look-up table for future requests. Note that this call
442 overwrites any existing entry in the cache whereas __call__ will try
443 to use an entry in the cache if it already exists
444
445 @param identifier: XACML function namespace
446 @type identifier: basestring
447 """
448
449
450
451 _capitalize = lambda s: s[0].upper() + s[1:]
452
453
454
455 functionName = identifier.split(self.__class__.URN_SEP)[-1]
456 typePart = functionName.split(self.__class__.FUNCTION_NS_SUFFIX)[0]
457
458
459 typeName = _capitalize(typePart)
460
461
462 if '-' in typeName:
463 typeName = ''.join([_capitalize(i) for i in typeName.split('-')])
464
465 typeURI = AttributeValue.TYPE_URI_MAP.get(typeName)
466 if typeURI is None:
467
468
469 if typePart in SPECIAL_TYPE_MAP:
470 typeURI = AttributeValue.TYPE_URI_MAP[
471 SPECIAL_TYPE_MAP[typePart]]
472 else:
473 raise TypeError('No AttributeValue.TYPE_URI_MAP entry for '
474 '%r type' % typePart)
475
476 _type = self.attributeValueClassFactory(typeURI)
477 if _type is None:
478 raise TypeError('No AttributeValue.TYPE_MAP entry for %r type' %
479 typeName)
480
481 className = typeName + self.functionSuffix
482 classVars = {
483 'TYPE': _type,
484 'FUNCTION_NS': identifier
485 }
486
487 functionClass = type(className,
488 (self.__class__.FUNCTION_BASE_CLASS, ),
489 classVars)
490
491 self.__map[identifier] = functionClass
492
494 """Return the class for the given XACML type function identifier
495
496 @param identifier: XACML *-at-least-one-member-of type function
497 identifier
498 @type identifier: basestring
499 @return: at least one member of class corresponding to the given input
500 identifier
501 @rtype: AtLeastOneMemberOfBase derived type or None if no match is
502 found
503 """
504
505 functionClass = self.__map.get(identifier)
506 if functionClass is None:
507
508
509 self.loadFunction(identifier)
510
511
512
513 return self.__map.get(identifier)
514
517 """Generic Error exception class for FunctionMap"""
518
521 """Configuration related exception for FunctionMap"""
522
525 """Map function IDs to their class implementations in the various function
526 sub-modules. It provide a layer over the various
527 FunctionClassFactoryInterface implementations so that a function class can
528 be obtained directly from a given XACML function URN.
529
530 @cvar FUNCTION_PKG_PREFIX: python package path for functions package
531 @type FUNCTION_PKG_PREFIX: string
532
533 @cvar V1_0_PKG_PREFIX: python package path for XACML 1.0 functions package
534 @type V1_0_PKG_PREFIX: string
535
536 @cvar V2_0_PKG_PREFIX: python package path for XACML 2.0 functions package
537 @type V2_0_PKG_PREFIX: string
538
539 @cvar SUPPORTED_NSS: mapping of function URN prefix to Python package
540 @type SUPPORTED_NSS: dict
541
542 @cvar FUNCTION_CLASS_FACTORY_CLASSNAME: standard name for class factory
543 which should be present in each generic function module. This factory is
544 invoked to create the function class for any given function URN related to
545 that module
546 @type FUNCTION_CLASS_FACTORY_CLASSNAME: string
547 """
548 FUNCTION_PKG_PREFIX = 'ndg.xacml.core.functions.'
549
550 V1_0_PKG_PREFIX = FUNCTION_PKG_PREFIX + 'v1.'
551 V2_0_PKG_PREFIX = FUNCTION_PKG_PREFIX + 'v2.'
552
553 SUPPORTED_NSS = {
554 AbstractFunction.V1_0_FUNCTION_NS: V1_0_PKG_PREFIX,
555 AbstractFunction.V2_0_FUNCTION_NS: V2_0_PKG_PREFIX
556 }
557
558
559
560 FUNCTION_CLASS_FACTORY_CLASSNAME = 'FunctionClassFactory'
561
563 """Force type for dictionary key value pairs: function values must be
564 of AbstractFunction derived type and ID keys string type
565 """
566
567
568
569 VettedDict.__init__(self, self.keyFilter, self.valueFilter)
570
571
572
573
574
575
576
577 self.__classFactoryMap = {}
578 self.__custom_class_factory_map = {}
579
580 @staticmethod
582 """Enforce string type keys
583
584 @param key: function URN
585 @type key: basestring
586 @return: True for valid key type
587 @rtype: bool
588 @raise TypeError: invalid key type
589 """
590 if not isinstance(key, basestring):
591 raise TypeError('Expecting %r type for key; got %r' %
592 (basestring, type(key)))
593
594 return True
595
596 @staticmethod
598 """Enforce AbstractFunction derived types for match functions
599
600 @param value: function URN
601 @type value: ndg.xacml.core.functions.AbstractFunction / NotImplemented
602 @return: True for valid function type
603 @rtype: bool
604 @raise TypeError: invlaid key type
605 """
606 if value is NotImplemented:
607 return True
608
609 elif not issubclass(value, AbstractFunction):
610 raise TypeError('Expecting %r derived type for value; got %r' %
611 (AbstractFunction, value))
612
613 return True
614
620
622 """Get package to retrieve function class for the given XACML function
623 namespace
624
625 @param functionNs: XACML function namespace
626 @type functionNs: basestring
627 """
628
629 if functionNs in self:
630 return self[functionNs]
631
632
633
634 functionFactory = self.__classFactoryMap.get(functionNs)
635 if functionFactory is not None:
636
637 self[functionNs] = functionFactory(functionNs)
638 return
639
640
641 cls = FunctionMap
642 classPath = None
643
644 for namespacePrefix, pkgNamePrefix in cls.SUPPORTED_NSS.items():
645 if functionNs.startswith(namespacePrefix):
646
647
648 functionName = functionNs.split(namespacePrefix)[-1]
649 functionNameParts = functionName.split('-')
650
651 if len(functionNameParts) == 1:
652 moduleName = functionNameParts[0]
653 else:
654 prefix = None
655
656
657 for pfx in SPECIAL_TYPE_MAP.iterkeys():
658 pfxsep = pfx + '-'
659 if functionName.startswith(pfxsep):
660 prefix = pfxsep
661 break
662 if prefix:
663 suffix = functionName[len(prefix):]
664 moduleName = '_'.join(suffix.split('-')).lower()
665 else:
666 moduleName = '_'.join(functionNameParts[1:]).lower()
667
668 classPath = pkgNamePrefix + moduleName + '.' + \
669 cls.FUNCTION_CLASS_FACTORY_CLASSNAME
670 break
671
672 if classPath is None:
673 raise FunctionMapConfigError('Namespace for function not '
674 'recognised: %r' % functionNs)
675
676
677 try:
678 functionFactory = callModuleObject(classPath)
679
680 except (ImportError, AttributeError), e:
681 log.error("Error importing function factory class %r for function "
682 "identifier %r: %s", classPath, functionNs, str(e))
683
684
685 self[functionNs] = NotImplemented
686 else:
687 function = functionFactory(functionNs)
688 if function is None:
689 raise unsupportedFunctionErrorFactory(functionNs)
690
691 self[functionNs] = function
692 self.__classFactoryMap[functionNs] = functionFactory
693
694 - def load_custom_function(self,
695 function_ns,
696 function_factory=None,
697 function_factory_path=None):
698 """Add a user defined function to the list of functions supported"""
699
700 if function_ns in XacmlFunctionNames.FUNCTION_NAMES:
701 raise OverwritingStdFunctionError("Attempting to overwrite the "
702 "standard function namespace %r"
703 "with a new custom function" %
704 function_ns)
705 if function_factory is None:
706 if not isinstance(function_factory_path, basestring):
707 raise TypeError('Expecting "function_factory_path" keyword '
708 'set to string function factory path; got %r' %
709 function_factory_path)
710 try:
711 function_factory = callModuleObject(function_factory_path)
712
713 except (ImportError, AttributeError), e:
714 log.error("Error importing function factory class %r for custom "
715 "function identifier %r: %s", function_factory_path,
716 function_ns, str(e))
717 raise
718
719 function = function_factory(function_ns)
720 if function is None:
721 raise unsupportedFunctionErrorFactory(function_ns)
722
723 self[function_ns] = function
724 self.__custom_class_factory_map[function_ns] = function_factory
725
727 """Override base class implementation to load and cache function classes
728 if they don't otherwise exist
729
730 @param key: function URN
731 @type key: basestring
732 @return: function class
733 @rtype: ndg.xacml.core.functions.AbstractFunction / NotImplemented
734 """
735 functionClass = VettedDict.get(self, key)
736 if functionClass is None:
737 self.loadFunction(key)
738
739 return VettedDict.__getitem__(self, key)
740
741 - def get(self, key, *arg):
742 """Likewise to __getitem__, enable loading and caching of function
743 classes if they don't otherwise exist
744
745 @param key: XACML function URN
746 @type key: basestring
747 @param arg: set a single additional argument if required which is
748 used as the default value should the key not be found in the map
749 @type arg: tuple
750 @return: function class
751 @rtype: ndg.xacml.core.functions.AbstractFunction / NotImplemented
752 """
753 functionClass = VettedDict.get(self, key, *arg)
754 if functionClass is None:
755 self.loadFunction(key)
756 return VettedDict.get(self, key, *arg)
757 else:
758 return functionClass
759
760
761
762 functionMap = FunctionMap()
763