Push SAML Attribute namespace configuration into the resolver. (Needed for proper...
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / attrresolv / provider / SimpleBaseAttributeDefinition.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 /*
27  * Contributed by SunGard SCT.
28  */
29
30 package edu.internet2.middleware.shibboleth.aa.attrresolv.provider;
31
32 import java.security.Principal;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.Iterator;
36 import java.util.LinkedHashSet;
37 import java.util.Set;
38
39 import javax.naming.NamingEnumeration;
40 import javax.naming.NamingException;
41 import javax.naming.directory.Attribute;
42 import javax.naming.directory.Attributes;
43
44 import org.apache.log4j.Logger;
45 import org.w3c.dom.Element;
46
47 import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeDefinitionPlugIn;
48 import edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies;
49 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolutionPlugInException;
50 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
51
52 /**
53  * This is an abstract class that all other attribute definitions in this package extend. It provides processing of
54  * common attributes as well as dependency resolutions.
55  * 
56  * @author <a href="mailto:vgoenka@sungardsct.com">Vishal Goenka </a>
57  */
58 abstract class SimpleBaseAttributeDefinition extends BaseAttributeDefinition implements AttributeDefinitionPlugIn {
59
60         private static Logger log = Logger.getLogger(SimpleBaseAttributeDefinition.class.getName());
61
62         protected ValueHandler valueHandler;
63         protected String connectorMapping;
64
65         protected SimpleBaseAttributeDefinition(Element e) throws ResolutionPlugInException {
66
67                 super(e);
68
69                 String sourceName = e.getAttribute("sourceName");
70                 if (sourceName == null || sourceName.equals("")) {
71                         int index = getId().lastIndexOf("#");
72                         if (index < 0) {
73                                 index = getId().lastIndexOf(":");
74                                 int slashIndex = getId().lastIndexOf("/");
75                                 if (slashIndex > index) {
76                                         index = slashIndex;
77                                 }
78                         }
79                         connectorMapping = getId().substring(index + 1);
80                 } else {
81                         connectorMapping = sourceName;
82                 }
83
84                 String valueHandlerSpec = e.getAttribute("valueHandler");
85
86                 if (valueHandlerSpec != null && !valueHandlerSpec.equals("")) {
87                         try {
88                                 Class handlerClass = Class.forName(valueHandlerSpec);
89                                 valueHandler = (ValueHandler) handlerClass.newInstance();
90                         } catch (ClassNotFoundException cnfe) {
91                                 log.error("Value Handler implementation specified for attribute (" + getId() + ") cannot be found: "
92                                                 + cnfe);
93                                 throw new ResolutionPlugInException("Value Handler implementation specified for attribute (" + getId()
94                                                 + ") cannot be found.");
95                         } catch (Exception oe) {
96                                 log.error("Value Handler implementation specified for attribute (" + getId()
97                                                 + ") coudl not be loaded: " + oe);
98                                 throw new ResolutionPlugInException("Value Handler implementation specified for attribute (" + getId()
99                                                 + ") could not be loaded.");
100                         }
101                 }
102
103                 if (valueHandler != null) {
104                         log.debug("Custom Value Handler enabled for attribute (" + getId() + ").");
105                 }
106
107         }
108
109         protected Collection resolveDependencies(ResolverAttribute attribute, Principal principal, String requester,
110                         Dependencies depends) throws ResolutionPlugInException {
111
112                 log.debug("Resolving attribute: (" + getId() + ")");
113
114                 Set results = new LinkedHashSet();
115                 if (!connectorDependencyIds.isEmpty()) {
116                         results.addAll(Arrays.asList(getValuesFromConnectors(depends)));
117                 }
118
119                 if (!attributeDependencyIds.isEmpty()) {
120                         results.addAll(Arrays.asList(getValuesFromAttributes(depends)));
121                 }
122
123                 if (valueHandler != null) {
124                         attribute.registerValueHandler(valueHandler);
125                 }
126
127                 return results;
128         }
129
130         protected Object[] getValuesFromAttributes(Dependencies depends) {
131
132                 Set results = new LinkedHashSet();
133
134                 Iterator attrDependIt = attributeDependencyIds.iterator();
135                 while (attrDependIt.hasNext()) {
136                         ResolverAttribute attribute = depends.getAttributeResolution((String) attrDependIt.next());
137                         if (attribute != null) {
138                                 log.debug("Found value(s) for attribute (" + getId() + ").");
139                                 for (Iterator iterator = attribute.getValues(); iterator.hasNext();) {
140                                         results.add(iterator.next());
141                                 }
142                         } else {
143                                 log.error("An attribute dependency of attribute (" + getId()
144                                                 + ") was not included in the dependency chain.");
145                         }
146                 }
147
148                 if (results.isEmpty()) {
149                         log.debug("An attribute dependency of attribute (" + getId() + ") supplied no values.");
150                 }
151                 return results.toArray();
152         }
153
154         protected Object[] getValuesFromConnectors(Dependencies depends) {
155
156                 Set results = new LinkedHashSet();
157
158                 Iterator connectorDependIt = connectorDependencyIds.iterator();
159                 while (connectorDependIt.hasNext()) {
160                         Attributes attrs = depends.getConnectorResolution((String) connectorDependIt.next());
161                         if (attrs != null) {
162                                 Attribute attr = attrs.get(connectorMapping);
163                                 if (attr != null) {
164                                         log.debug("Found value(s) for attribute (" + getId() + ").");
165                                         try {
166                                                 NamingEnumeration valuesEnum = attr.getAll();
167                                                 while (valuesEnum.hasMore()) {
168                                                         results.add(valuesEnum.next());
169                                                 }
170                                         } catch (NamingException e) {
171                                                 log.error("An problem was encountered resolving the dependencies of attribute (" + getId()
172                                                                 + "): " + e);
173                                         }
174                                 }
175                         }
176                 }
177
178                 if (results.isEmpty()) {
179                         log.debug("A connector dependency of attribute (" + getId() + ") supplied no values.");
180                 }
181                 return results.toArray();
182         }
183
184         protected String getString(Object value) {
185
186                 // if (value instanceof String) return (String)value;
187                 // This was inspired by the fact that certain attributes (such as userPassword, when read using JNDI) are
188                 // returned
189                 // from data connectors as byte [] rather than String, and doing a .toString() returns something like
190                 // B[@aabljadj,
191                 // which is a reference to the array, rather than the string value.
192                 if (value instanceof byte[]) return new String((byte[]) value);
193                 return value.toString();
194         }
195
196 }