2 * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation
3 * for Advanced Internet Development, Inc. All rights reserved
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution, if any, must include
15 * the following acknowledgment: "This product includes software developed by
16 * the University Corporation for Advanced Internet Development
17 * <http://www.ucaid.edu> Internet2 Project. Alternately, this acknowledegement
18 * may appear in the software itself, if and wherever such third-party
19 * acknowledgments normally appear.
21 * Neither the name of Shibboleth nor the names of its contributors, nor
22 * Internet2, nor the University Corporation for Advanced Internet Development,
23 * Inc., nor UCAID may be used to endorse or promote products derived from this
24 * software without specific prior written permission. For written permission,
25 * please contact shibboleth@shibboleth.org
27 * Products derived from this software may not be called Shibboleth, Internet2,
28 * UCAID, or the University Corporation for Advanced Internet Development, nor
29 * may Shibboleth appear in their name, without prior written permission of the
30 * University Corporation for Advanced Internet Development.
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
36 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
37 * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
38 * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
39 * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY
40 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 package edu.internet2.middleware.shibboleth.common;
49 import java.util.HashMap;
51 import java.util.Properties;
53 import org.apache.log4j.Logger;
54 import org.w3c.dom.Element;
55 import org.w3c.dom.NodeList;
58 * @author Walter Hoehn
61 public class ServiceProviderMapper {
63 private static Logger log = Logger.getLogger(ShibbolethOriginConfig.class.getName());
64 private ShibbolethOriginConfig configuration;
65 private Credentials credentials;
66 private Map relyingParties = new HashMap();
68 public ServiceProviderMapper(Element rawConfig, ShibbolethOriginConfig configuration, Credentials credentials)
69 throws ServiceProviderMapperException {
71 this.configuration = configuration;
72 this.credentials = credentials;
74 NodeList itemElements =
75 rawConfig.getElementsByTagNameNS(ShibbolethOriginConfig.originConfigNamespace, "RelyingParty");
77 for (int i = 0; i < itemElements.getLength(); i++) {
78 addRelyingParty((Element) itemElements.item(i));
81 //Verify we have a proper default party
83 configuration.getConfigProperty(
84 "edu.internet2.middleware.shibboleth.common.RelyingParty.defaultRelyingParty");
85 if (defaultParty == null || defaultParty.equals("")) {
86 if (relyingParties.size() != 1) {
88 "Default Relying Party not specified. Add a (defaultRelyingParty) attribute to <ShibbolethOriginConfig>.");
89 throw new ServiceProviderMapperException("Required configuration not specified.");
91 log.debug("Only one Relying Party loaded. Using this as the default.");
94 log.debug("Default Relying Party set to: (" + defaultParty + ").");
95 if (!relyingParties.containsKey(defaultParty)) {
96 log.error("Default Relying Party refers to a Relying Party that has not been loaded.");
97 throw new ServiceProviderMapperException("Invalid configuration (Default Relying Party).");
101 private void addRelyingParty(Element e) throws ServiceProviderMapperException {
103 log.debug("Found a Relying Party.");
104 //TODO catch these individually and don't totally fail for one bad
105 if (e.getLocalName().equals("RelyingParty")) {
106 RelyingParty party = new RelyingPartyImpl(e, configuration, credentials);
107 log.debug("Relying Party (" + party.getName() + ") loaded.");
108 relyingParties.put(party.getName(), party);
111 public RelyingParty getRelyingParty(String providerIdFromTarget) {
113 //If the target did not send a Provider Id, then assume it is a Shib
114 // 1.1 or older target
115 if (providerIdFromTarget == null || providerIdFromTarget.equals("")) {
116 log.info("Request is from legacy shib target. Selecting default Relying Party.");
117 return new LegacyWrapper(getDefaultRelyingPatry());
120 //Look for a configuration for the specific relying party
121 if (relyingParties.containsKey(providerIdFromTarget)) {
122 log.info("Found Relying Party for (" + providerIdFromTarget + ").");
123 return (RelyingParty) relyingParties.get(providerIdFromTarget);
126 //Next, check to see if the relying party is in any groups
127 RelyingParty groupParty = findRelyingPartyByGroup(providerIdFromTarget);
128 if (groupParty != null) {
129 log.info("Provider is a member of Relying Party (" + groupParty.getName() + ").");
130 return new RelyingPartyGroupWrapper(groupParty, providerIdFromTarget);
133 //OK, just send the default
135 "Could not locate Relying Party configuration for ("
136 + providerIdFromTarget
137 + "). Using default Relying Party.");
138 return new UnknownProviderWrapper(getDefaultRelyingPatry());
141 private RelyingParty findRelyingPartyByGroup(String providerIdFromTarget) {
143 // TODO This is totally a stub and needs to be based on target metadata lookup
144 if (providerIdFromTarget.startsWith("urn:mace:inqueue:")) {
145 if (relyingParties.containsKey("urn:mace:inqueue")) {
146 return (RelyingParty) relyingParties.get("urn:mace:inqueue");
152 private RelyingParty getDefaultRelyingPatry() {
154 //If there is no explicit default, pick the single configured Relying Party
155 String defaultParty =
156 configuration.getConfigProperty(
157 "edu.internet2.middleware.shibboleth.common.RelyingParty.defaultRelyingParty");
158 if (defaultParty == null || defaultParty.equals("")) {
159 return (RelyingParty) relyingParties.values().iterator().next();
162 //If we do have a default specified, use it...
163 return (RelyingParty) relyingParties.get(defaultParty);
166 class RelyingPartyImpl implements RelyingParty {
168 protected ShibbolethOriginConfig originConfig;
169 protected Properties partyOverrides = new Properties();
170 protected RelyingPartyIdentityProvider identityProvider;
171 protected String name;
173 public RelyingPartyImpl(Element partyConfig, ShibbolethOriginConfig globalConfig, Credentials credentials)
174 throws ServiceProviderMapperException {
176 //Use global config for defaults
177 this.originConfig = globalConfig;
180 name = ((Element) partyConfig).getAttribute("name");
181 if (name == null || name.equals("")) {
182 log.error("Relying Party name not set. Add a (name) attribute to <RelyingParty>.");
183 throw new ServiceProviderMapperException("Required configuration not specified.");
185 log.debug("Loading Relying Party: (" + name + ").");
187 //Load an credential for signing
188 String credentialName = ((Element) partyConfig).getAttribute("signingCredential");
189 Credential credential = credentials.getCredential(credentialName);
191 if (credential == null) {
192 if (credentialName == null || credentialName.equals("")) {
194 "Relying Party credential not set. Add a (signingCredential) attribute to <RelyingParty>.");
195 throw new ServiceProviderMapperException("Required configuration not specified.");
198 "Relying Party credential not set. Add a (signingCredential) attribute to <RelyingParty>.");
199 throw new ServiceProviderMapperException("Required configuration not specified.");
205 String attribute = ((Element) partyConfig).getAttribute("providerId");
206 if (attribute != null && !attribute.equals("")) {
207 log.debug("Overriding providerId for Relying Pary (" + name + ") with (" + attribute + ").");
208 partyOverrides.setProperty(
209 "edu.internet2.middleware.shibboleth.hs.HandleServlet.providerId",
213 attribute = ((Element) partyConfig).getAttribute("AAUrl");
214 if (attribute != null && !attribute.equals("")) {
215 log.debug("Overriding AAUrl for Relying Pary (" + name + ") with (" + attribute + ").");
216 partyOverrides.setProperty("edu.internet2.middleware.shibboleth.hs.HandleServlet.AAUrl", attribute);
220 new RelyingPartyIdentityProvider(
221 getConfigProperty("edu.internet2.middleware.shibboleth.hs.HandleServlet.providerId"),
225 public String getProviderId() {
229 public String getName() {
233 public boolean isLegacyProvider() {
237 public String getConfigProperty(String key) {
238 if (partyOverrides.containsKey(key)) {
239 return partyOverrides.getProperty(key);
241 return originConfig.getConfigProperty(key);
244 public String getHSNameFormatId() {
248 public IdentityProvider getIdentityProvider() {
249 return identityProvider;
252 class RelyingPartyIdentityProvider implements IdentityProvider {
254 private String providerId;
255 private Credential responseSigningCredential;
257 RelyingPartyIdentityProvider(String providerId, Credential responseSigningCred) {
258 this.providerId = providerId;
259 this.responseSigningCredential = responseSigningCred;
262 public String getProviderId() {
266 public Credential getResponseSigningCredential() {
267 return responseSigningCredential;
270 public Credential getAssertionSigningCredential() {
277 class RelyingPartyGroupWrapper implements RelyingParty {
279 private RelyingParty wrapped;
280 private String providerId;
282 RelyingPartyGroupWrapper(RelyingParty wrapped, String providerId) {
283 this.wrapped = wrapped;
284 this.providerId = providerId;
287 public String getName() {
288 return wrapped.getName();
291 public String getConfigProperty(String key) {
292 return wrapped.getConfigProperty(key);
295 public boolean isLegacyProvider() {
299 public String getHSNameFormatId() {
300 return wrapped.getHSNameFormatId();
303 public IdentityProvider getIdentityProvider() {
304 return wrapped.getIdentityProvider();
307 public String getProviderId() {
312 class UnknownProviderWrapper implements RelyingParty {
313 private RelyingParty wrapped;
315 UnknownProviderWrapper(RelyingParty wrapped) {
316 this.wrapped = wrapped;
319 public String getName() {
320 return wrapped.getName();
323 public String getConfigProperty(String key) {
324 return wrapped.getConfigProperty(key);
327 public boolean isLegacyProvider() {
328 return wrapped.isLegacyProvider();
331 public String getHSNameFormatId() {
332 return wrapped.getHSNameFormatId();
335 public IdentityProvider getIdentityProvider() {
336 return wrapped.getIdentityProvider();
339 public String getProviderId() {
344 class LegacyWrapper extends UnknownProviderWrapper {
346 LegacyWrapper(RelyingParty wrapped) {
349 public boolean isLegacyProvider() {