3f6b06ec4434927fde7edbb1ac95951fdff7deec
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / AAAttribute.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;
51
52
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.Collection;
56 import java.util.Iterator;
57 import java.util.List;
58
59 import org.apache.log4j.Logger;
60 import org.opensaml.SAMLAttribute;
61 import org.opensaml.SAMLException;
62 import org.opensaml.XML;
63 import org.w3c.dom.Document;
64 import org.w3c.dom.Element;
65 import org.w3c.dom.Node;
66
67 import edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute;
68 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
69 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandler;
70 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandlerException;
71
72 /**
73  * An attribute for which the Shibboleth Attribute Authority has been asked
74  * to provide an assertion.
75  * 
76  * @author Walter Hoehn (wassa@columbia.edu)
77  */
78 public class AAAttribute extends SAMLAttribute implements ResolverAttribute, ArpAttribute {
79
80         private static Logger log = Logger.getLogger(AAAttribute.class.getName());
81         private boolean resolved = false;
82         
83         public final static String SHIB_ATTRIBUTE_NAMESPACE_URI = "urn:mace:shibboleth:1.0:attributeNamespace:uri";
84         
85         /** Default lifetime, in seconds **/
86         private static long defaultLifetime = 1800; // 30 minutes
87         private ValueHandler valueHandler = new StringValueHandler();
88
89         public AAAttribute(String name) throws SAMLException {
90                 super(
91                         name,
92                         SHIB_ATTRIBUTE_NAMESPACE_URI,
93                         null,
94                         defaultLifetime,
95                         null);
96         }
97
98         public AAAttribute(String name, Object[] values) throws SAMLException {
99                 this(name);
100                 setValues(values);
101         }
102         
103         public AAAttribute(String name, Object[] values, ValueHandler handler) throws SAMLException {
104                         this(name);
105                         setValues(values);
106                         registerValueHandler(handler);
107                 }
108
109         public boolean hasValues() {
110                 if (values.isEmpty()) {
111                         return false;
112                 }
113                 return true;
114         }
115
116         public Iterator getValues() {
117                 return valueHandler.getValues(values);
118         }
119
120         public void setValues(Object[] values) {
121                 if (!this.values.isEmpty()) {
122                         this.values.clear();
123                 }
124                 List newList = Arrays.asList(values);
125                 if (newList.contains(null)) {
126                         newList.remove(null);
127                 }
128                 this.values.addAll(newList);
129         }
130
131         /**
132         * @see java.lang.Object#hashCode()
133         */
134         public int hashCode() {
135                 int code = 0;
136                 if (values != null) {
137                         Iterator iterator = values.iterator();
138                         while (iterator.hasNext()) {
139                                 code += iterator.next().hashCode();
140                         }
141                 }
142                 return name.hashCode() + code;
143         }
144
145         /**
146          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#resolved()
147          */
148         public boolean resolved() {
149                 return resolved;
150         }
151
152         /**
153          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#setResolved()
154          */
155         public void setResolved() {
156                 resolved = true;
157         }
158
159         /**
160          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#resolveFromCached(edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute)
161          */
162         public void resolveFromCached(ResolverAttribute attribute) {
163                 resolved = true;
164                 setLifetime(attribute.getLifetime());
165
166                 if (!this.values.isEmpty()) {
167                         this.values.clear();
168                 }
169                 for (Iterator iterator = attribute.getValues(); iterator.hasNext();) {
170                         values.add(iterator.next());
171                 }
172
173                 registerValueHandler(attribute.getRegisteredValueHandler());
174         }
175
176         public void setLifetime(long lifetime) {
177                 this.lifetime = lifetime;
178
179         }
180
181         public void addValue(Object value) {
182                 if (value != null) {
183                         values.add(value);
184                 }
185         }
186
187         /**
188          * @see org.opensaml.SAMLObject#toDOM(org.w3c.dom.Document)
189          */
190         public Node toDOM(Document doc, boolean xmlns) {
191
192                 Element attributeElement = doc.createElementNS(XML.SAML_NS, "Attribute");
193                 attributeElement.setAttributeNS(null, "AttributeName", name);
194                 attributeElement.setAttributeNS(null, "AttributeNamespace", namespace);
195
196                 for (int i = 0; i < values.size(); i++) {
197
198                         if (type != null) {
199                                 attributeElement.setAttributeNS(XML.XMLNS_NS, "xmlns:typens", type.getNamespaceURI());
200                         }
201                         Element valueElement = doc.createElementNS(XML.SAML_NS, "AttributeValue");
202                         if (type != null) {
203                                 valueElement.setAttributeNS(XML.XSI_NS, "xsi:type", "typens:" + type.getLocalName());
204                         }
205                         
206                         try {
207                                 valueHandler.toDOM(valueElement, values.get(i), doc);
208                                 attributeElement.appendChild(valueElement);
209
210                         } catch (ValueHandlerException e) {
211                                 log.error("Value Handler unable to convert value to DOM Node: " + e);
212                         }
213                 }
214                 return attributeElement;
215         }
216
217         /**
218          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#registerValueHandler(edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandler)
219          */
220         public void registerValueHandler(ValueHandler handler) {
221                 valueHandler = handler;
222         }
223
224         /**
225          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#getRegisteredValueHandler()
226          */
227         public ValueHandler getRegisteredValueHandler() {
228                 return valueHandler;
229         }
230
231         /**
232          * @see java.lang.Object#equals(java.lang.Object)
233          */
234         public boolean equals(Object object) {
235
236                 if (!(object instanceof AAAttribute)) {
237                         return false;
238                 }
239                 if (lifetime != ((AAAttribute) object).lifetime) {
240                         return false;
241                 }
242                 if (name != ((AAAttribute) object).name) {
243                         return false;
244                 }
245                 if (!valueHandler.equals(((AAAttribute) object).valueHandler)) {
246                         return false;
247                 }
248                 
249                 ArrayList localValues = new ArrayList();
250                 for (Iterator iterator = getValues();iterator.hasNext();) {
251                         localValues.add(iterator.next());
252                 }
253                 
254                 ArrayList objectValues = new ArrayList();
255                 for (Iterator iterator = ((AAAttribute) object).getValues();iterator.hasNext();) {
256                         objectValues.add(iterator.next());
257                 }
258                 
259                 return localValues.equals(objectValues);
260         }
261
262 }
263
264 /**
265  *  Default <code>ValueHandler</code> implementation.  Expects all values to be String objects.
266  *
267  * @author Walter Hoehn (wassa@columbia.edu)
268  */
269 class StringValueHandler implements ValueHandler {
270
271         public void toDOM(Element valueElement, Object value, Document document) {
272                 valueElement.appendChild(document.createTextNode(value.toString()));
273         }
274
275         public Iterator getValues(Collection internalValues) {
276                 return internalValues.iterator();
277         }
278
279         /**
280          * @see java.lang.Object#equals(java.lang.Object)
281          */
282         public boolean equals(Object object) {
283                 if (object instanceof StringValueHandler) {
284                         return true;
285                 }
286                 return false;
287         }
288
289 }
290
291