Push SAML Attribute namespace configuration into the resolver. (Needed for proper...
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / AAAttribute.java
1 /*
2  * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
3  * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
4  * provided that the following conditions are met: Redistributions of source code must retain the above copyright
5  * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above
6  * copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials
7  * provided with the distribution, if any, must include the following acknowledgment: "This product includes software
8  * developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2 Project.
9  * Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
10  * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2, nor
11  * the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
12  * products derived from this software without specific prior written permission. For written permission, please contact
13  * shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2, UCAID, or the
14  * University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name, without prior
15  * written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS PROVIDED BY THE
16  * COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE
18  * DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. IN NO
19  * EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC.
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 package edu.internet2.middleware.shibboleth.aa;
27
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Iterator;
32 import java.util.List;
33
34 import javax.xml.namespace.QName;
35
36 import org.apache.log4j.Logger;
37 import org.opensaml.SAMLAttribute;
38 import org.opensaml.SAMLException;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.Element;
41
42 import edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute;
43 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
44 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandler;
45 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandlerException;
46
47 /**
48  * An attribute for which the Shibboleth Attribute Authority has been asked to provide an assertion.
49  * 
50  * @author Walter Hoehn (wassa@columbia.edu)
51  */
52 public class AAAttribute extends SAMLAttribute implements ResolverAttribute, ArpAttribute {
53
54         private static Logger log = Logger.getLogger(AAAttribute.class.getName());
55         private boolean resolved = false;
56
57         /** Default lifetime, in seconds * */
58         private static long defaultLifetime = 1800; // 30 minutes
59         private ValueHandler valueHandler = new StringValueHandler();
60
61         /**
62          * Constructs a skeleton attribute with no values.
63          * 
64          * @param name
65          *            the name of the attribute
66          * @param legacyCompat
67          *            boolean indicator of whether or not the legacy namespace hack should be used (this is required for SPs
68          *            running old versions of xerces)
69          * @throws SAMLException
70          */
71         public AAAttribute(String name, boolean legacyCompat) throws SAMLException {
72
73                 super(name, null, legacyCompat ? new QName("urn:mace:shibboleth:1.0",
74                                 "AttributeValueType") : null, defaultLifetime, null);
75         }
76
77         /**
78          * Constructs a skeleton attribute with no values.
79          * 
80          * @param name
81          *            the name of the attribute
82          * @throws SAMLException
83          *             if the attribute could not be created
84          */
85         public AAAttribute(String name) throws SAMLException {
86
87                 super(name, null, null, defaultLifetime, null);
88         }
89
90         public AAAttribute(String name, Object[] values) throws SAMLException {
91
92                 this(name);
93                 setValues(values);
94         }
95
96         public AAAttribute(String name, Object[] values, ValueHandler handler) throws SAMLException {
97
98                 this(name);
99                 setValues(values);
100                 registerValueHandler(handler);
101         }
102
103         public boolean hasValues() {
104
105                 if (values.isEmpty()) { return false; }
106                 return true;
107         }
108
109         public Iterator getValues() {
110
111                 return valueHandler.getValues(values);
112         }
113
114         public void setValues(Object[] values) {
115
116                 if (!this.values.isEmpty()) {
117                         this.values.clear();
118                 }
119                 List newList = Arrays.asList(values);
120                 if (newList.contains(null)) {
121                         newList.remove(null);
122                 }
123                 this.values.addAll(newList);
124         }
125
126         /**
127          * @see java.lang.Object#hashCode()
128          */
129         public int hashCode() {
130
131                 int code = 0;
132                 if (values != null) {
133                         Iterator iterator = values.iterator();
134                         while (iterator.hasNext()) {
135                                 code += iterator.next().hashCode();
136                         }
137                 }
138                 return name.hashCode() + code;
139         }
140
141         /**
142          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#resolved()
143          */
144         public boolean resolved() {
145
146                 return resolved;
147         }
148
149         /**
150          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#setResolved()
151          */
152         public void setResolved() {
153
154                 resolved = true;
155         }
156
157         /**
158          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#resolveFromCached(edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute)
159          */
160         public void resolveFromCached(ResolverAttribute attribute) {
161
162                 resolved = true;
163                 setLifetime(attribute.getLifetime());
164
165                 if (!this.values.isEmpty()) {
166                         this.values.clear();
167                 }
168                 for (Iterator iterator = attribute.getValues(); iterator.hasNext();) {
169                         values.add(iterator.next());
170                 }
171
172                 registerValueHandler(attribute.getRegisteredValueHandler());
173         }
174
175         public void setLifetime(long lifetime) {
176
177                 this.lifetime = lifetime;
178
179         }
180
181         public void addValue(Object value) {
182
183                 if (value != null) {
184                         values.add(value);
185                 }
186         }
187
188         /*
189          * @see org.opensaml.SAMLAttribute#valueToDOM(int, org.w3c.dom.Element)
190          */
191         protected void valueToDOM(int index, Element e) throws SAMLException {
192
193                 try {
194                         valueHandler.toDOM(e, values.get(index), e.getOwnerDocument());
195
196                 } catch (ValueHandlerException ex) {
197                         log.error("Value Handler unable to convert value to DOM Node: " + ex);
198                 }
199         }
200
201         /**
202          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#registerValueHandler(edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandler)
203          */
204         public void registerValueHandler(ValueHandler handler) {
205
206                 valueHandler = handler;
207         }
208
209         /**
210          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#getRegisteredValueHandler()
211          */
212         public ValueHandler getRegisteredValueHandler() {
213
214                 return valueHandler;
215         }
216
217         /**
218          * @see java.lang.Object#equals(java.lang.Object)
219          */
220         public boolean equals(Object object) {
221
222                 if (!(object instanceof AAAttribute)) { return false; }
223                 if (lifetime != ((AAAttribute) object).lifetime) { return false; }
224                 if (!name.equals(((AAAttribute) object).name)) { return false; }
225                 if (!valueHandler.equals(((AAAttribute) object).valueHandler)) { return false; }
226
227                 ArrayList localValues = new ArrayList();
228                 for (Iterator iterator = getValues(); iterator.hasNext();) {
229                         localValues.add(iterator.next());
230                 }
231
232                 ArrayList objectValues = new ArrayList();
233                 for (Iterator iterator = ((AAAttribute) object).getValues(); iterator.hasNext();) {
234                         objectValues.add(iterator.next());
235                 }
236
237                 return localValues.equals(objectValues);
238         }
239
240 }
241
242 /**
243  * Default <code>ValueHandler</code> implementation. Expects all values to be String objects.
244  * 
245  * @author Walter Hoehn (wassa@columbia.edu)
246  */
247
248 class StringValueHandler implements ValueHandler {
249
250         public void toDOM(Element valueElement, Object value, Document document) {
251
252                 valueElement.appendChild(document.createTextNode(value.toString()));
253         }
254
255         public Iterator getValues(Collection internalValues) {
256
257                 return internalValues.iterator();
258         }
259
260         /**
261          * @see java.lang.Object#equals(java.lang.Object)
262          */
263         public boolean equals(Object object) {
264
265                 if (object instanceof StringValueHandler) { return true; }
266                 return false;
267         }
268
269 }