ARP Rule marshalling imporovements.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / arp / Rule.java
1 /* 
2  * The Shibboleth License, Version 1. 
3  * Copyright (c) 2002 
4  * University Corporation for Advanced Internet Development, Inc. 
5  * All rights reserved
6  * 
7  * 
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions are met:
10  * 
11  * Redistributions of source code must retain the above copyright notice, this 
12  * list of conditions and the following disclaimer.
13  * 
14  * Redistributions in binary form must reproduce the above copyright notice, 
15  * this list of conditions and the following disclaimer in the documentation 
16  * and/or other materials provided with the distribution, if any, must include 
17  * the following acknowledgment: "This product includes software developed by 
18  * the University Corporation for Advanced Internet Development 
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
20  * may appear in the software itself, if and wherever such third-party 
21  * acknowledgments normally appear.
22  * 
23  * Neither the name of Shibboleth nor the names of its contributors, nor 
24  * Internet2, nor the University Corporation for Advanced Internet Development, 
25  * Inc., nor UCAID may be used to endorse or promote products derived from this 
26  * software without specific prior written permission. For written permission, 
27  * please contact shibboleth@shibboleth.org
28  * 
29  * Products derived from this software may not be called Shibboleth, Internet2, 
30  * UCAID, or the University Corporation for Advanced Internet Development, nor 
31  * may Shibboleth appear in their name, without prior written permission of the 
32  * University Corporation for Advanced Internet Development.
33  * 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 package edu.internet2.middleware.shibboleth.aa.arp;
51
52 import java.net.URI;
53 import java.net.URISyntaxException;
54 import java.net.URL;
55
56 import org.apache.log4j.Logger;
57 import org.apache.xerces.parsers.DOMParser;
58 import org.w3c.dom.CharacterData;
59 import org.w3c.dom.Document;
60 import org.w3c.dom.Element;
61 import org.w3c.dom.Node;
62 import org.w3c.dom.NodeList;
63
64 /**
65  *  An Attribute Release Policy Rule.
66  *
67  * @author Walter Hoehn (wassa@columbia.edu)
68  */
69
70 public class Rule {
71
72         private String description;
73         private Target target;
74         private static Logger log = Logger.getLogger(Rule.class.getName());
75
76         /**
77          * Returns the description for this <code>Rule</code>.
78          * @return String
79          */
80
81         public String getDescription() {
82                 return description;
83         }
84
85         /**
86          * Sets the description for this <code>Rule</code>.
87          * @param description The description to set
88          */
89
90         public void setDescription(String description) {
91                 this.description = description;
92         }
93
94         /**
95          * Unmarshalls the <code>Rule</code> into an xml <code>Element</code>.
96          * @return the xml <code>Element</code>
97          */
98
99         public Element unmarshall() {
100
101                 DOMParser parser = new DOMParser();
102                 Document placeHolder = parser.getDocument();
103                 Element ruleNode = placeHolder.createElement("Rule");
104
105                 if (description != null) {
106                         Element descriptionNode = placeHolder.createElement("Description");
107                         descriptionNode.appendChild(placeHolder.createTextNode(description));
108                         ruleNode.appendChild(descriptionNode);
109                 }
110
111                 return ruleNode;
112         }
113
114         /**
115          * Creates an ARP Rule from an xml representation.
116          * @param the xml <code>Element</code> containing the ARP Rule.
117          */
118
119         public void marshall(Element element) throws ArpMarshallingException {
120
121                 //Make sure we are dealing with a Rule
122                 if (!element.getTagName().equals("Rule")) {
123                         log.error("Element data does not represent an ARP Rule.");
124                         throw new ArpMarshallingException("Element data does not represent an ARP Rule.");
125                 }
126
127                 //Grab the description
128                 NodeList descriptionNodes = element.getElementsByTagName("Description");
129                 if (descriptionNodes.getLength() > 0) {
130                         Element descriptionNode = (Element) descriptionNodes.item(0);
131                         if (descriptionNode.hasChildNodes()
132                                 && descriptionNode.getFirstChild().getNodeType() == Node.TEXT_NODE) {
133                                 description = ((CharacterData) descriptionNode.getFirstChild()).getData();
134                         }
135                 }
136
137                 //Create the Target
138                 NodeList targetNodes = element.getElementsByTagName("Target");
139                 if (targetNodes.getLength() != 1) {
140                         log.error(
141                                 "Element data does not represent an ARP Rule.  An ARP Rule must contain 1 and "
142                                         + "only 1 Target definition.");
143                         throw new ArpMarshallingException(
144                                 "Element data does not represent an ARP Rule.  An"
145                                         + " ARP Rule must contain 1 and only 1 Target definition.");
146                 }
147                 target = new Target();
148                 target.marshall((Element) targetNodes.item(0));
149         }
150
151         /**
152          * Method matchesRequest.
153          * @param requester
154          * @param resource
155          * @return boolean
156          */
157         public boolean matchesRequest(String requester, URL resource) {
158                 if (target.matchesAny()) {
159                         return true;
160                 }
161                 try {
162                         MatchFunction requesterFunction =
163                                 ArpEngine.lookupMatchFunction(target.getRequester().getMatchFunctionIdentifier());
164                         if (!requesterFunction.match(target.getRequester().getValue(), requester)) {
165                                 return false;
166                         }
167                         if (target.getResource().matchesAny()) {
168                                 return true;
169                         }
170                         MatchFunction resourceFunction =
171                                 ArpEngine.lookupMatchFunction(target.getResource().getMatchFunctionIdentifier());
172                         if (resourceFunction.match(target.getResource().getValue(), resource)) {
173                                 return true;
174                         }
175                         return false;
176                 } catch (ArpException e) {
177                         log.warn("Encountered a problem while trying to find matching ARP rules: " + e);
178                         return false;
179                 }
180         }
181
182         class Target {
183                 private Requester requester = null;
184                 private Resource resource = null;
185                 private boolean matchesAny = false;
186
187                 void marshall(Element element) throws ArpMarshallingException {
188
189                         //Make sure we are deling with a Target
190                         if (!element.getTagName().equals("Target")) {
191                                 log.error("Element data does not represent an ARP Rule Target.");
192                                 throw new ArpMarshallingException("Element data does not represent an ARP Rule target.");
193                         }
194                         
195                         //Handle <AnyTarget/> definitions
196                         NodeList anyTargetNodeList = element.getElementsByTagName("AnyTarget");
197                         if (anyTargetNodeList.getLength() == 1) {
198                                         matchesAny = true;
199                                         return;
200                         }
201
202                         //Create Requester
203                         NodeList requesterNodeList = element.getElementsByTagName("Requester");
204                         if (requesterNodeList.getLength() == 1) {
205                                 requester = new Requester();
206                                 requester.marshall((Element) requesterNodeList.item(0));
207                         } else {
208                                 log.error("ARP Rule Target contains invalid data: incorrectly specified <Requester>.");
209                                 throw new ArpMarshallingException("ARP Rule Target contains invalid data: incorrectly specified <Requester>.");
210                         }
211                         
212                         //Handle <AnyResource/>
213                         NodeList anyResourceNodeList = element.getElementsByTagName("AnyResource");
214                         if (anyResourceNodeList.getLength() == 1) {
215                                         resource = new Resource();
216                                         return;
217                         }
218                         
219                         //Create Resource
220                         NodeList resourceNodeList = element.getElementsByTagName("Resource");
221                         if (resourceNodeList.getLength() == 1) {
222                                 resource = new Resource();
223                                 resource.marshall((Element) resourceNodeList.item(0));
224                         } else {
225                                 log.error("ARP Rule Target contains invalid data: incorrectly specified <Resource>.");
226                                 throw new ArpMarshallingException("ARP Rule Target contains invalid data: incorrectly specified <Resource>.");
227                         }
228                 }
229
230                 boolean matchesAny() {
231                         return matchesAny;
232                 }
233                 Requester getRequester() {
234                         return requester;
235                 }
236                 Resource getResource() {
237                         return resource;
238                 }
239         }
240
241         class Resource {
242                 private String value;
243                 private URI matchFunctionIdentifier;
244                 private boolean matchesAny;
245                 Resource() {
246                         matchesAny = true;      
247                 }
248                 boolean matchesAny() {
249                         return matchesAny;
250                 }
251                 URI getMatchFunctionIdentifier() {
252                         return matchFunctionIdentifier;
253                 }
254                 String getValue() {
255                         return value;
256                 }
257                 void marshall(Element element) throws ArpMarshallingException {
258                         //Make sure we are deling with a Resource
259                         if (!element.getTagName().equals("Resource")) {
260                                 log.error("Element data does not represent an ARP Rule Target.");
261                                 throw new ArpMarshallingException("Element data does not represent an ARP Rule target.");
262                         }
263                         
264                         //Grab the value
265                         if (element.hasChildNodes() && element.getFirstChild().getNodeType() == Node.TEXT_NODE) {
266                                 value = ((CharacterData) element.getFirstChild()).getData();
267                         } else {
268                                 log.error("Element data does not represent an ARP Rule Target.");
269                                 throw new ArpMarshallingException("Element data does not represent an ARP Rule target.");
270                         }
271                         
272                         //Grab the match function
273                         try {
274                                 if (element.hasAttribute("matchFunction")) {
275                                         matchFunctionIdentifier = new URI(element.getAttribute("matchFunction"));
276                                 } else {
277                                         matchFunctionIdentifier = new URI("urn:mace:shibboleth:arp:matchFunction:resourceTree");
278                                 }
279                         } catch (URISyntaxException e) {
280                                 log.error("ARP match function not identified by a proper URI.");
281                                 throw new ArpMarshallingException("ARP match function not identified by a proper URI.");
282                         }
283                 }
284         }
285
286         class Requester {
287                 private String value;
288                 private URI matchFunctionIdentifier;
289                 URI getMatchFunctionIdentifier() {
290                         return matchFunctionIdentifier;
291                 }
292                 String getValue() {
293                         return value;
294                 }
295                 void marshall(Element element) throws ArpMarshallingException {
296                         //Make sure we are deling with a Requester
297                         if (!element.getTagName().equals("Requester")) {
298                                 log.error("Element data does not represent an ARP Rule Target.");
299                                 throw new ArpMarshallingException("Element data does not represent an ARP Rule target.");
300                         }
301                         
302                         //Grab the value
303                         if (element.hasChildNodes() && element.getFirstChild().getNodeType() == Node.TEXT_NODE) {
304                                 value = ((CharacterData) element.getFirstChild()).getData();
305                         } else {
306                                 log.error("Element data does not represent an ARP Rule Target.");
307                                 throw new ArpMarshallingException("Element data does not represent an ARP Rule target.");
308                         }
309                         
310                         //Grab the match function
311                         try {
312                                 if (element.hasAttribute("matchFunction")) {
313                                         matchFunctionIdentifier = new URI(element.getAttribute("matchFunction"));
314                                 } else {
315                                         matchFunctionIdentifier = new URI("urn:mace:shibboleth:arp:matchFunction:exactShar");
316                                 }
317                         } catch (URISyntaxException e) {
318                                 log.error("ARP match function not identified by a proper URI.");
319                                 throw new ArpMarshallingException("ARP match function not identified by a proper URI.");
320                         }
321                 }
322         }
323
324 }