1 | ''' |
---|
2 | Created on 24 Feb 2010 |
---|
3 | |
---|
4 | @author: pjkersha |
---|
5 | ''' |
---|
6 | from ndg.xacml.utils import TypedList |
---|
7 | """NDG Security Target type definition |
---|
8 | |
---|
9 | NERC DataGrid |
---|
10 | """ |
---|
11 | __author__ = "P J Kershaw" |
---|
12 | __date__ = "25/02/10" |
---|
13 | __copyright__ = "(C) 2010 Science and Technology Facilities Council" |
---|
14 | __contact__ = "Philip.Kershaw@stfc.ac.uk" |
---|
15 | __license__ = "BSD - see LICENSE file in top-level directory" |
---|
16 | __contact__ = "Philip.Kershaw@stfc.ac.uk" |
---|
17 | __revision__ = "$Id$" |
---|
18 | import logging |
---|
19 | log = logging.getLogger(__name__) |
---|
20 | |
---|
21 | from ndg.xacml.core import XacmlCoreBase |
---|
22 | from ndg.xacml.core.action import Action |
---|
23 | from ndg.xacml.core.resource import Resource |
---|
24 | from ndg.xacml.core.subject import Subject |
---|
25 | from ndg.xacml.core.environment import Environment |
---|
26 | |
---|
27 | |
---|
28 | class Target(XacmlCoreBase): |
---|
29 | """XACML Target element""" |
---|
30 | ELEMENT_LOCAL_NAME = "Target" |
---|
31 | SUBJECTS_ELEMENT_LOCAL_NAME = "Subjects" |
---|
32 | ACTIONS_ELEMENT_LOCAL_NAME = "Actions" |
---|
33 | RESOURCES_ELEMENT_LOCAL_NAME = "Resources" |
---|
34 | ENVIRONMENTS_ELEMENT_LOCAL_NAME = "Environments" |
---|
35 | CHILD_ATTRS = ('subjects', 'resources', 'actions', 'environments') |
---|
36 | |
---|
37 | __slots__ = ('__subjects', '__resources', '__actions', '__environments') |
---|
38 | |
---|
39 | def __init__(self): |
---|
40 | """Initial attributes""" |
---|
41 | self.__subjects = TypedList(Subject) |
---|
42 | self.__resources = TypedList(Resource) |
---|
43 | self.__actions = TypedList(Action) |
---|
44 | self.__environments = TypedList(Environment) |
---|
45 | |
---|
46 | @property |
---|
47 | def subjects(self): |
---|
48 | return self.__subjects |
---|
49 | |
---|
50 | @property |
---|
51 | def resources(self): |
---|
52 | return self.__resources |
---|
53 | |
---|
54 | @property |
---|
55 | def actions(self): |
---|
56 | return self.__actions |
---|
57 | |
---|
58 | @property |
---|
59 | def environments(self): |
---|
60 | return self.__environments |
---|
61 | |
---|
62 | def match(self, request): |
---|
63 | """Generic method to match a <Target> element to the request context |
---|
64 | |
---|
65 | @param target: XACML target element |
---|
66 | @type target: ndg.xacml.core.target.Target |
---|
67 | @param request: XACML request context |
---|
68 | @type request: ndg.xacml.core.context.request.Request |
---|
69 | @return: True if request context matches the given target, |
---|
70 | False otherwise |
---|
71 | @rtype: bool |
---|
72 | """ |
---|
73 | |
---|
74 | # From section 5.5 of the XACML 2.0 Core Spec: |
---|
75 | # |
---|
76 | # For the parent of the <Target> element to be applicable to the |
---|
77 | # decision request, there MUST be at least one positive match between |
---|
78 | # each section of the <Target> element and the corresponding section of |
---|
79 | # the <xacml-context:Request> element. |
---|
80 | # |
---|
81 | # Also, 7.6: |
---|
82 | # |
---|
83 | # The target value SHALL be "Match" if the subjects, resources, actions |
---|
84 | # and environments specified in the target all match values in the |
---|
85 | # request context. |
---|
86 | statusValues = [False]*len(self.__class__.CHILD_ATTRS) |
---|
87 | |
---|
88 | # Iterate for target subjects, resources, actions and environments |
---|
89 | # elements |
---|
90 | for i, attrName in enumerate(self.__class__.CHILD_ATTRS): |
---|
91 | # If any one of the <Target> children is missing then it counts as |
---|
92 | # a match e.g. for <Subjects> child element - Section 5.5: |
---|
93 | # |
---|
94 | # <Subjects> [Optional] Matching specification for the subject |
---|
95 | # attributes in the context. If this element is missing, |
---|
96 | # then the target SHALL match all subjects. |
---|
97 | targetElem = getattr(self, attrName) |
---|
98 | if len(targetElem) == 0: |
---|
99 | statusValues[i] = True |
---|
100 | continue |
---|
101 | |
---|
102 | # Iterate over each for example, subject in the list of subjects: |
---|
103 | # <Target> |
---|
104 | # <Subjects> |
---|
105 | # <Subject> |
---|
106 | # ... |
---|
107 | # </Subject> |
---|
108 | # <Subject> |
---|
109 | # ... |
---|
110 | # </Subject> |
---|
111 | # ... |
---|
112 | # or resource in the list of resources and so on |
---|
113 | for targetSubElem in targetElem: |
---|
114 | |
---|
115 | # For the given subject/resource/action/environment check for a |
---|
116 | # match with the equivalent in the request |
---|
117 | requestElem = getattr(request, attrName) |
---|
118 | for requestSubElem in requestElem: |
---|
119 | if self._matchChild(targetSubElem, request): |
---|
120 | # Within the list of e.g. subjects if one subject |
---|
121 | # matches then this counts as a subject match overall |
---|
122 | # for this target |
---|
123 | statusValues[i] = True |
---|
124 | |
---|
125 | # Target matches if all the children (i.e. subjects, resources, actions |
---|
126 | # and environment sections) have at least one match. Otherwise it |
---|
127 | # doesn't count as a match |
---|
128 | return all(statusValues) |
---|
129 | |
---|
130 | def _matchChild(self, targetChild, request): |
---|
131 | """Match a request child element (a <Subject>, <Resource>, <Action> or |
---|
132 | <Environment>) with the corresponding target's <Subject>, <Resource>, |
---|
133 | <Action> or <Environment>. |
---|
134 | |
---|
135 | @param targetChild: Target Subject, Resource, Action or Environment |
---|
136 | object |
---|
137 | @type targetChild: ndg.xacml.core.TargetChildBase |
---|
138 | @param requestChild: Request Subject, Resource, Action or Environment |
---|
139 | object |
---|
140 | @type requestChild: ndg.xacml.core.context.RequestChildBase |
---|
141 | @return: True if request context matches something in the target |
---|
142 | @rtype: bool |
---|
143 | @raise UnsupportedStdFunctionError: policy references a function type |
---|
144 | which is in the XACML spec. but is not supported by this implementation |
---|
145 | @raise UnsupportedFunctionError: policy references a function type which |
---|
146 | is not supported by this implementation |
---|
147 | """ |
---|
148 | if targetChild is None: |
---|
149 | # Default if target child is not set is to match all children |
---|
150 | return True |
---|
151 | |
---|
152 | matchStatusValues = [True]*len(targetChild.matches) |
---|
153 | |
---|
154 | # Section 7.6 |
---|
155 | # |
---|
156 | # A subject, resource, action or environment SHALL match a value in the |
---|
157 | # request context if the value of all its <SubjectMatch>, |
---|
158 | # <ResourceMatch>, <ActionMatch> or <EnvironmentMatch> elements, |
---|
159 | # respectively, are "True". |
---|
160 | # |
---|
161 | # e.g. for <SubjectMatch>es in <Subject> ... |
---|
162 | for i, childMatch in enumerate(targetChild.matches): |
---|
163 | matchStatusValues[i] = childMatch.evaluate(request) |
---|
164 | |
---|
165 | # Any match => overall match |
---|
166 | return any(matchStatusValues) |
---|
167 | |
---|