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
6 * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
7 * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
8 * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu> Internet2
9 * Project. 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,
11 * nor 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
13 * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
14 * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
15 * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
16 * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
18 * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
19 * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
20 * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
23 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
27 package edu.internet2.middleware.shibboleth.common;
31 import java.util.HashMap;
34 import org.apache.log4j.Logger;
35 import org.w3c.dom.Element;
37 import edu.internet2.middleware.shibboleth.aa.AARelyingParty;
38 import edu.internet2.middleware.shibboleth.hs.HSRelyingParty;
39 import edu.internet2.middleware.shibboleth.idp.IdPConfig;
40 import edu.internet2.middleware.shibboleth.metadata.Metadata;
41 import edu.internet2.middleware.shibboleth.metadata.Provider;
44 * Base class for determining the effective relying party from the unique id of the service provider. Checks first for
45 * an exact match on the service provider, then for membership in a federation. Uses the default relying party if
48 * @author Walter Hoehn
50 public abstract class ServiceProviderMapper {
52 private static Logger log = Logger.getLogger(ServiceProviderMapper.class.getName());
53 protected Map relyingParties = new HashMap();
54 private Metadata metaData;
59 public ServiceProviderMapper(Metadata metaData) {
60 this.metaData = metaData;
63 protected abstract IdPConfig getOriginConfig();
65 protected void verifyDefaultParty(IdPConfig configuration) throws ServiceProviderMapperException {
66 //Verify we have a proper default party
67 String defaultParty = configuration.getDefaultRelyingPartyName();
68 if (defaultParty == null || defaultParty.equals("")) {
69 if (relyingParties.size() != 1) {
71 .error("Default Relying Party not specified. Add a (defaultRelyingParty) attribute to <IdPConfig>.");
72 throw new ServiceProviderMapperException("Required configuration not specified.");
74 log.debug("Only one Relying Party loaded. Using this as the default.");
77 log.debug("Default Relying Party set to: (" + defaultParty + ").");
78 if (!relyingParties.containsKey(defaultParty)) {
79 log.error("Default Relying Party refers to a Relying Party that has not been loaded.");
80 throw new ServiceProviderMapperException("Invalid configuration (Default Relying Party).");
84 protected RelyingParty getRelyingPartyImpl(String providerIdFromTarget) {
86 //Null request, send the default
87 if (providerIdFromTarget == null) {
88 RelyingParty relyingParty = getDefaultRelyingParty();
89 log.info("Using default Relying Party: (" + relyingParty.getName() + ").");
90 return new UnknownProviderWrapper(relyingParty, providerIdFromTarget);
93 //Look for a configuration for the specific relying party
94 if (relyingParties.containsKey(providerIdFromTarget)) {
95 log.info("Found Relying Party for (" + providerIdFromTarget + ").");
96 return (RelyingParty) relyingParties.get(providerIdFromTarget);
99 //Next, check to see if the relying party is in any groups
100 RelyingParty groupParty = findRelyingPartyByGroup(providerIdFromTarget);
101 if (groupParty != null) {
102 log.info("Provider is a member of Relying Party (" + groupParty.getName() + ").");
103 return new RelyingPartyGroupWrapper(groupParty, providerIdFromTarget);
106 //OK, we can't find it... just send the default
107 RelyingParty relyingParty = getDefaultRelyingParty();
108 log.info("Could not locate Relying Party configuration for (" + providerIdFromTarget
109 + "). Using default Relying Party: (" + relyingParty.getName() + ").");
110 return new UnknownProviderWrapper(relyingParty, providerIdFromTarget);
113 private RelyingParty findRelyingPartyByGroup(String providerIdFromTarget) {
115 Provider provider = metaData.lookup(providerIdFromTarget);
116 if (provider != null) {
117 String[] groups = provider.getGroups();
118 for (int i = 0; groups.length > i; i++) {
119 //We need to iterate backward because the groups go from least to most specific
120 String group = groups[groups.length - 1 - i];
121 if (relyingParties.containsKey(group)) {
122 log.info("Found matching Relying Party for group (" + group + ").");
123 return (RelyingParty) relyingParties.get(group);
126 .debug("Provider is a member of group (" + group
127 + "), but no matching Relying Party was found.");
134 public RelyingParty getDefaultRelyingParty() {
136 //If there is no explicit default, pick the single configured Relying
138 String defaultParty = getOriginConfig().getDefaultRelyingPartyName();
139 if (defaultParty == null || defaultParty.equals("")) {
140 return (RelyingParty) relyingParties.values().iterator().next();
143 //If we do have a default specified, use it...
144 return (RelyingParty) relyingParties.get(defaultParty);
148 * Base relying party implementation.
150 * @author Walter Hoehn
152 protected abstract class BaseRelyingPartyImpl implements RelyingParty {
154 protected RelyingPartyIdentityProvider identityProvider;
155 protected String name;
156 protected String overridenOriginProviderId;
158 public BaseRelyingPartyImpl(Element partyConfig) throws ServiceProviderMapperException {
161 name = ((Element) partyConfig).getAttribute("name");
162 if (name == null || name.equals("")) {
163 log.error("Relying Party name not set. Add a (name) attribute to <RelyingParty>.");
164 throw new ServiceProviderMapperException("Required configuration not specified.");
166 log.debug("Loading Relying Party: (" + name + ").");
168 //Process overrides for global data
169 String attribute = ((Element) partyConfig).getAttribute("providerId");
170 if (attribute != null && !attribute.equals("")) {
171 log.debug("Overriding providerId for Relying Pary (" + name + ") with (" + attribute + ").");
172 overridenOriginProviderId = attribute;
177 public String getProviderId() {
181 public String getName() {
185 public IdentityProvider getIdentityProvider() {
186 return identityProvider;
190 * Default identity provider implementation.
192 * @author Walter Hoehn
194 protected class RelyingPartyIdentityProvider implements IdentityProvider {
196 private String providerId;
197 private Credential responseSigningCredential;
198 private Credential assertionSigningCredential;
200 public RelyingPartyIdentityProvider(String providerId, Credential responseSigningCred) {
201 this.providerId = providerId;
202 this.responseSigningCredential = responseSigningCred;
205 public RelyingPartyIdentityProvider(String providerId, Credential responseSigningCred,
206 Credential assertionSigningCred) {
207 this.providerId = providerId;
208 this.responseSigningCredential = responseSigningCred;
209 this.assertionSigningCredential = assertionSigningCred;
212 public String getProviderId() {
216 public Credential getResponseSigningCredential() {
217 return responseSigningCredential;
220 public Credential getAssertionSigningCredential() {
221 return assertionSigningCredential;
228 * Relying party implementation wrapper for relying parties that are federations.
230 * @author Walter Hoehn
232 class RelyingPartyGroupWrapper implements RelyingParty, HSRelyingParty, AARelyingParty {
234 private RelyingParty wrapped;
235 private String providerId;
237 RelyingPartyGroupWrapper(RelyingParty wrapped, String providerId) {
238 this.wrapped = wrapped;
239 this.providerId = providerId;
242 public String getName() {
243 return wrapped.getName();
246 public boolean isLegacyProvider() {
250 public IdentityProvider getIdentityProvider() {
251 return wrapped.getIdentityProvider();
254 public String getProviderId() {
258 public String getHSNameFormatId() {
259 if (!(wrapped instanceof HSRelyingParty)) {
262 return ((HSRelyingParty) wrapped).getHSNameFormatId();
265 public URL getAAUrl() {
266 if (!(wrapped instanceof HSRelyingParty)) {
269 return ((HSRelyingParty) wrapped).getAAUrl();
272 public URI getDefaultAuthMethod() {
273 if (!(wrapped instanceof HSRelyingParty)) {
276 return ((HSRelyingParty) wrapped).getDefaultAuthMethod();
279 public boolean passThruErrors() {
280 if (!(wrapped instanceof AARelyingParty)) {
283 return ((AARelyingParty) wrapped).passThruErrors();
288 * Relying party implementation wrapper for anonymous service providers.
290 * @author Walter Hoehn
292 protected class UnknownProviderWrapper implements RelyingParty, HSRelyingParty, AARelyingParty {
294 protected RelyingParty wrapped;
295 protected String providerId;
297 protected UnknownProviderWrapper(RelyingParty wrapped, String providerId) {
298 this.wrapped = wrapped;
299 this.providerId = providerId;
302 public String getName() {
303 return wrapped.getName();
306 public IdentityProvider getIdentityProvider() {
307 return wrapped.getIdentityProvider();
310 public String getProviderId() {
314 public String getHSNameFormatId() {
315 if (!(wrapped instanceof HSRelyingParty)) {
318 return ((HSRelyingParty) wrapped).getHSNameFormatId();
321 public boolean isLegacyProvider() {
322 if (!(wrapped instanceof HSRelyingParty)) {
325 return ((HSRelyingParty) wrapped).isLegacyProvider();
328 public URL getAAUrl() {
329 if (!(wrapped instanceof HSRelyingParty)) {
332 return ((HSRelyingParty) wrapped).getAAUrl();
335 public URI getDefaultAuthMethod() {
336 if (!(wrapped instanceof HSRelyingParty)) {
339 return ((HSRelyingParty) wrapped).getDefaultAuthMethod();
342 public boolean passThruErrors() {
343 if (!(wrapped instanceof AARelyingParty)) {
346 return ((AARelyingParty) wrapped).passThruErrors();